diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 64047defa1..f1f79ef269 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,16 +13,19 @@ #/avm/ptn/avd-lza/networking/ @Azure/avm-ptn-avd-lza-networking-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/session-hosts/ @Azure/avm-ptn-avd-lza-sessionhosts-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep -/avm/ptn/azd/container-apps/ @Azure/avm-ptn-azd-containerapps-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-ai-environment/ @Azure/avm-ptn-azd-mlaienvironment-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/finops-toolkit/finops-hub/ @Azure/avm-ptn-finopstoolkit-finopshub-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/lz/sub-vending/ @Azure/avm-ptn-lz-subvending-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/network/hub-networking/ @Azure/avm-ptn-network-hubnetworking-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/network/private-link-private-dns-zones/ @Azure/avm-ptn-network-privatelinkprivatednszones-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/policy-insights/remediation/ @Azure/avm-ptn-policyinsights-remediation-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/security/security-center/ @Azure/avm-ptn-security-securitycenter-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/virtual-machine-images/azure-image-builder/ @Azure/avm-ptn-virtualmachineimages-azureimagebuilder-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/aad/domain-service/ @Azure/avm-res-aad-domainservice-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/alerts-management/action-rule/ @Azure/avm-res-alertsmanagement-actionrule-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/analysis-services/server/ @Azure/avm-res-analysisservices-server-module-owners-bicep @Azure/avm-module-reviewers-bicep @@ -61,14 +64,17 @@ /avm/res/desktop-virtualization/host-pool/ @Azure/avm-res-desktopvirtualization-hostpool-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/desktop-virtualization/scaling-plan/ @Azure/avm-res-desktopvirtualization-scalingplan-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/desktop-virtualization/workspace/ @Azure/avm-res-desktopvirtualization-workspace-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/dev-ops-infrastructure/pool/ @Azure/avm-res-devopsinfrastructure-pool-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/dev-test-lab/lab/ @Azure/avm-res-devtestlab-lab-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/digital-twins/digital-twins-instance/ @Azure/avm-res-digitaltwins-digitaltwinsinstance-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/document-db/database-account/ @Azure/avm-res-documentdb-databaseaccount-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/document-db/mongo-cluster/ @Azure/avm-res-documentdb-mongocluster-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/domain/ @Azure/avm-res-eventgrid-domain-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/namespace/ @Azure/avm-res-eventgrid-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/system-topic/ @Azure/avm-res-eventgrid-systemtopic-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/topic/ @Azure/avm-res-eventgrid-topic-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-hub/namespace/ @Azure/avm-res-eventhub-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/fabric/capacity/ @Azure/avm-res-fabric-capacity-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/health-bot/health-bot/ @Azure/avm-res-healthbot-healthbot-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/healthcare-apis/workspace/ @Azure/avm-res-healthcareapis-workspace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/hybrid-compute/machine/ @Azure/avm-res-hybridcompute-machine-module-owners-bicep @Azure/avm-module-reviewers-bicep @@ -130,6 +136,7 @@ /avm/res/network/virtual-network-gateway/ @Azure/avm-res-network-virtualnetworkgateway-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/network/virtual-wan/ @Azure/avm-res-network-virtualwan-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/network/vpn-gateway/ @Azure/avm-res-network-vpngateway-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/network/vpn-server-configuration/ @Azure/avm-res-network-vpnserverconfiguration-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/network/vpn-site/ @Azure/avm-res-network-vpnsite-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/operational-insights/workspace/ @Azure/avm-res-operationalinsights-workspace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/operations-management/solution/ @Azure/avm-res-operationsmanagement-solution-module-owners-bicep @Azure/avm-module-reviewers-bicep @@ -144,6 +151,7 @@ /avm/res/search/search-service/ @Azure/avm-res-search-searchservice-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/service-bus/namespace/ @Azure/avm-res-servicebus-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/service-fabric/cluster/ @Azure/avm-res-servicefabric-cluster-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/service-networking/traffic-controller/ @Azure/avm-res-servicenetworking-trafficcontroller-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/signal-r-service/signal-r/ @Azure/avm-res-signalrservice-signalr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/signal-r-service/web-pub-sub/ @Azure/avm-res-signalrservice-webpubsub-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/sql/instance-pool/ @Azure/avm-res-sql-instancepool-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index ff7d4ca5f9..da881057cf 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -48,16 +48,19 @@ body: # - "avm/ptn/avd-lza/networking" # - "avm/ptn/avd-lza/session-hosts" - "avm/ptn/azd/apim-api" - - "avm/ptn/azd/container-apps" + - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - "avm/ptn/azd/ml-ai-environment" + - "avm/ptn/azd/ml-hub-dependencies" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" - "avm/ptn/finops-toolkit/finops-hub" - "avm/ptn/lz/sub-vending" + - "avm/ptn/network/hub-networking" - "avm/ptn/network/private-link-private-dns-zones" - "avm/ptn/policy-insights/remediation" - "avm/ptn/security/security-center" + - "avm/ptn/virtual-machine-images/azure-image-builder" - "avm/res/aad/domain-service" - "avm/res/alerts-management/action-rule" - "avm/res/analysis-services/server" @@ -96,14 +99,17 @@ body: - "avm/res/desktop-virtualization/host-pool" - "avm/res/desktop-virtualization/scaling-plan" - "avm/res/desktop-virtualization/workspace" + - "avm/res/dev-ops-infrastructure/pool" - "avm/res/dev-test-lab/lab" - "avm/res/digital-twins/digital-twins-instance" - "avm/res/document-db/database-account" + - "avm/res/document-db/mongo-cluster" - "avm/res/event-grid/domain" - "avm/res/event-grid/namespace" - "avm/res/event-grid/system-topic" - "avm/res/event-grid/topic" - "avm/res/event-hub/namespace" + - "avm/res/fabric/capacity" - "avm/res/health-bot/health-bot" - "avm/res/healthcare-apis/workspace" - "avm/res/hybrid-compute/machine" @@ -165,6 +171,7 @@ body: - "avm/res/network/virtual-network-gateway" - "avm/res/network/virtual-wan" - "avm/res/network/vpn-gateway" + - "avm/res/network/vpn-server-configuration" - "avm/res/network/vpn-site" - "avm/res/operational-insights/workspace" - "avm/res/operations-management/solution" @@ -179,6 +186,7 @@ body: - "avm/res/search/search-service" - "avm/res/service-bus/namespace" - "avm/res/service-fabric/cluster" + - "avm/res/service-networking/traffic-controller" - "avm/res/signal-r-service/signal-r" - "avm/res/signal-r-service/web-pub-sub" - "avm/res/sql/instance-pool" diff --git a/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml b/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml index d7f47a87e5..aed8ec0c1e 100644 --- a/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml +++ b/.github/workflows/avm.ptn.aca-lza.hosting-environment.yml @@ -26,7 +26,6 @@ on: push: branches: - main - - avm-ptn-acalza-hostingenvironment paths: - ".github/actions/templates/avm-**" - ".github/workflows/avm.template.module.yml" diff --git a/.github/workflows/avm.ptn.azd.container-apps-stack.yml b/.github/workflows/avm.ptn.azd.container-apps-stack.yml new file mode 100644 index 0000000000..7a057fef70 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.container-apps-stack.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.container-apps-stack" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.container-apps-stack.yml" + - "avm/ptn/azd/container-apps-stack/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/container-apps-stack" + workflowPath: ".github/workflows/avm.ptn.azd.container-apps-stack.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.ptn.azd.container-apps.yml b/.github/workflows/avm.ptn.network.hub-networking.yml similarity index 90% rename from .github/workflows/avm.ptn.azd.container-apps.yml rename to .github/workflows/avm.ptn.network.hub-networking.yml index 0759231151..617646aa74 100644 --- a/.github/workflows/avm.ptn.azd.container-apps.yml +++ b/.github/workflows/avm.ptn.network.hub-networking.yml @@ -1,5 +1,4 @@ -name: "avm.ptn.azd.container-apps" - +name: "avm.ptn.network.hub-networking" on: workflow_dispatch: inputs: @@ -28,19 +27,16 @@ on: paths: - ".github/actions/templates/avm-**" - ".github/workflows/avm.template.module.yml" - - ".github/workflows/avm.ptn.azd.container-apps.yml" - - "avm/ptn/azd/container-apps/**" + - ".github/workflows/avm.ptn.network.hub-networking.yml" + - "avm/ptn/network/hub-networking/**" - "avm/utilities/pipelines/**" - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" - env: - modulePath: "avm/ptn/azd/container-apps" - workflowPath: ".github/workflows/avm.ptn.azd.container-apps.yml" - + modulePath: "avm/ptn/network/hub-networking" + workflowPath: ".github/workflows/avm.ptn.network.hub-networking.yml" concurrency: group: ${{ github.workflow }} - jobs: ########################### # Initialize pipeline # @@ -68,7 +64,6 @@ jobs: moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} modulePath: "${{ env.modulePath }}" - ############################## # Call reusable workflow # ############################## diff --git a/.github/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml b/.github/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml new file mode 100644 index 0000000000..445bdfa481 --- /dev/null +++ b/.github/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.virtual-machine-images.azure-image-builder" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.virtual-machine-images.azure-image-builder.yml" + - "avm/ptn/virtual-machine-images/azure-image-builder/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/virtual-machine-images/azure-image-builder" + workflowPath: ".github/workflows/avm.ptn.virtual-machine-images.azure-image-builder.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.dev-ops-infrastructure.pool.yml b/.github/workflows/avm.res.dev-ops-infrastructure.pool.yml new file mode 100644 index 0000000000..dac40abeb8 --- /dev/null +++ b/.github/workflows/avm.res.dev-ops-infrastructure.pool.yml @@ -0,0 +1,88 @@ +name: "avm.res.dev-ops-infrastructure.pool" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.dev-ops-infrastructure.pool.yml" + - "avm/res/dev-ops-infrastructure/pool/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/dev-ops-infrastructure/pool" + workflowPath: ".github/workflows/avm.res.dev-ops-infrastructure.pool.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.document-db.mongo-cluster.yml b/.github/workflows/avm.res.document-db.mongo-cluster.yml new file mode 100644 index 0000000000..f7b513ae03 --- /dev/null +++ b/.github/workflows/avm.res.document-db.mongo-cluster.yml @@ -0,0 +1,88 @@ +name: "avm.res.document-db.mongo-cluster" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.document-db.mongo-cluster.yml" + - "avm/res/document-db/mongo-cluster/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/document-db/mongo-cluster" + workflowPath: ".github/workflows/avm.res.document-db.mongo-cluster.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.fabric.capacity.yml b/.github/workflows/avm.res.fabric.capacity.yml new file mode 100644 index 0000000000..778c48160b --- /dev/null +++ b/.github/workflows/avm.res.fabric.capacity.yml @@ -0,0 +1,89 @@ +name: "avm.res.fabric.capacity" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.fabric.capacity.yml" + - "avm/res/fabric/capacity/**" + - "avm/res/fabric/capacity/topic/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/fabric/capacity" + workflowPath: ".github/workflows/avm.res.fabric.capacity.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.application-gateway.yml b/.github/workflows/avm.res.network.application-gateway.yml index 2439e1ab16..095cf15ade 100644 --- a/.github/workflows/avm.res.network.application-gateway.yml +++ b/.github/workflows/avm.res.network.application-gateway.yml @@ -25,7 +25,6 @@ on: push: branches: - main - - avm-application-gateway paths: - ".github/actions/templates/avm-**" - ".github/workflows/avm.template.module.yml" diff --git a/.github/workflows/avm.res.network.vpn-server-configuration.yml b/.github/workflows/avm.res.network.vpn-server-configuration.yml new file mode 100644 index 0000000000..785cee942d --- /dev/null +++ b/.github/workflows/avm.res.network.vpn-server-configuration.yml @@ -0,0 +1,88 @@ +name: "avm.res.network.vpn-server-configuration" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.network.vpn-server-configuration.yml" + - "avm/res/network/vpn-server-configuration/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/network/vpn-server-configuration" + workflowPath: ".github/workflows/avm.res.network.vpn-server-configuration.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.service-networking.traffic-controller.yml b/.github/workflows/avm.res.service-networking.traffic-controller.yml new file mode 100644 index 0000000000..775de7a740 --- /dev/null +++ b/.github/workflows/avm.res.service-networking.traffic-controller.yml @@ -0,0 +1,88 @@ +name: "avm.res.service-networking.traffic-controller" + +on: + 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 + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.service-networking.traffic-controller.yml" + - "avm/res/service-networking/traffic-controller/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/service-networking/traffic-controller" + workflowPath: ".github/workflows/avm.res.service-networking.traffic-controller.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/platform.ossf-scorecard.yml b/.github/workflows/platform.ossf-scorecard.yml index 5c37e5fc09..b6f8d9fa50 100644 --- a/.github/workflows/platform.ossf-scorecard.yml +++ b/.github/workflows/platform.ossf-scorecard.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5 + uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2 with: name: SARIF file path: results.sarif @@ -68,6 +68,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12 with: sarif_file: results.sarif diff --git a/.github/workflows/platform.publish-module-index-json.yml b/.github/workflows/platform.publish-module-index-json.yml index b6a510c1f0..2d2d3eac69 100644 --- a/.github/workflows/platform.publish-module-index-json.yml +++ b/.github/workflows/platform.publish-module-index-json.yml @@ -74,7 +74,7 @@ jobs: } - name: Upload artifacts - uses: actions/upload-artifact@v4.3.5 + uses: actions/upload-artifact@v4.4.2 with: name: publish-module-index-json-artifacts path: | diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e02c76f6c..05509ca25f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "editor.formatOnSave": true, + "editor.bracketPairColorization.enabled": true, "files.trimTrailingWhitespace": true, "files.autoSave": "onFocusChange", "files.eol": "\n", diff --git a/avm/ptn/aca-lza/hosting-environment/README.md b/avm/ptn/aca-lza/hosting-environment/README.md index 4754ccdb4d..4dd7f7ba52 100644 --- a/avm/ptn/aca-lza/hosting-environment/README.md +++ b/avm/ptn/aca-lza/hosting-environment/README.md @@ -144,7 +144,7 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment: -via JSON Parameter file +via JSON parameters file ```json { @@ -215,6 +215,41 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/aca-lza/hosting-environment:' + +// Required parameters +param applicationGatewayCertificateKeyName = 'appgwcert' +param enableApplicationInsights = true +param enableDaprInstrumentation = false +param spokeApplicationGatewaySubnetAddressPrefix = '10.1.3.0/24' +param spokeInfraSubnetAddressPrefix = '10.1.0.0/23' +param spokePrivateEndpointsSubnetAddressPrefix = '10.1.2.0/27' +param spokeVNetAddressPrefixes = [ + '10.1.0.0/22' +] +param vmAdminPassword = '' +param vmAdminUsername = 'vmadmin' +param vmJumpBoxSubnetAddressPrefix = '10.1.2.32/27' +param vmLinuxSshAuthorizedKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC9QWdPia7CYYWWX/+eRrLKzGtQ+tjelZfDlbHy/Dg98 konstantinospantos@KonstaninossMBP.localdomain' +param vmSize = 'Standard_B1s' +// Non-required parameters +param location = '' +param tags = { + environment: 'test' +} +param vmAuthenticationType = 'sshPublicKey' +param vmJumpboxOSType = 'linux' +param workloadName = '' +``` + +
+

+ ### Example 2: _Using a hub and spoke deployment._ This instance deploys the module including a Hub to peer to. @@ -267,7 +302,7 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -359,6 +394,48 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/aca-lza/hosting-environment:' + +// Required parameters +param applicationGatewayCertificateKeyName = 'appgwcert' +param enableApplicationInsights = true +param enableDaprInstrumentation = false +param spokeApplicationGatewaySubnetAddressPrefix = '10.1.3.0/24' +param spokeInfraSubnetAddressPrefix = '10.1.0.0/23' +param spokePrivateEndpointsSubnetAddressPrefix = '10.1.2.0/27' +param spokeVNetAddressPrefixes = [ + '10.1.0.0/22' +] +param vmAdminPassword = '' +param vmAdminUsername = 'vmadmin' +param vmJumpBoxSubnetAddressPrefix = '10.1.2.32/27' +param vmLinuxSshAuthorizedKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC9QWdPia7CYYWWX/+eRrLKzGtQ+tjelZfDlbHy/Dg98 konstantinospantos@KonstaninossMBP.localdomain' +param vmSize = 'Standard_B1s' +// Non-required parameters +param deployZoneRedundantResources = true +param enableDdosProtection = true +param environment = 'dev' +param exposeContainerAppsWith = 'applicationGateway' +param hubVirtualNetworkResourceId = '' +param location = '' +param networkApplianceIpAddress = '' +param storageAccountType = 'Premium_LRS' +param tags = { + environment: 'test' +} +param vmAuthenticationType = 'sshPublicKey' +param vmJumpboxOSType = 'linux' +param workloadName = '' +``` + +
+

+ ### Example 3: _Using all the available options in WAF aligned values._ This instance deploys the module with the all the available parameters in WAF aligned values. @@ -409,7 +486,7 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -495,6 +572,46 @@ module hostingEnvironment 'br/public:avm/ptn/aca-lza/hosting-environment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/aca-lza/hosting-environment:' + +// Required parameters +param applicationGatewayCertificateKeyName = 'appgwcert' +param enableApplicationInsights = true +param enableDaprInstrumentation = false +param spokeApplicationGatewaySubnetAddressPrefix = '10.1.3.0/24' +param spokeInfraSubnetAddressPrefix = '10.1.0.0/23' +param spokePrivateEndpointsSubnetAddressPrefix = '10.1.2.0/27' +param spokeVNetAddressPrefixes = [ + '10.1.0.0/22' +] +param vmAdminPassword = '' +param vmAdminUsername = 'vmadmin' +param vmJumpBoxSubnetAddressPrefix = '10.1.2.32/27' +param vmLinuxSshAuthorizedKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC9QWdPia7CYYWWX/+eRrLKzGtQ+tjelZfDlbHy/Dg98 konstantinospantos@KonstaninossMBP.localdomain' +param vmSize = 'Standard_B1s' +// Non-required parameters +param deployZoneRedundantResources = true +param enableDdosProtection = true +param environment = 'dev' +param exposeContainerAppsWith = 'applicationGateway' +param location = '' +param storageAccountType = 'Premium_LRS' +param tags = { + environment: 'test' +} +param vmAuthenticationType = 'sshPublicKey' +param vmJumpboxOSType = 'linux' +param workloadName = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/ai-platform/baseline/README.md b/avm/ptn/ai-platform/baseline/README.md index 45718c8a77..7676df01c3 100644 --- a/avm/ptn/ai-platform/baseline/README.md +++ b/avm/ptn/ai-platform/baseline/README.md @@ -38,7 +38,6 @@ By integrating with Microsoft Entra ID for secure identity management and utiliz | `Microsoft.MachineLearningServices/workspaces` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01-preview/workspaces) | | `Microsoft.MachineLearningServices/workspaces/computes` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2022-10-01/workspaces/computes) | | `Microsoft.Maintenance/configurationAssignments` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Maintenance/2023-04-01/configurationAssignments) | -| `Microsoft.ManagedIdentity/userAssignedIdentities` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities) | | `Microsoft.Network/bastionHosts` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-11-01/bastionHosts) | | `Microsoft.Network/networkInterfaces` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkInterfaces) | | `Microsoft.Network/networkSecurityGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/networkSecurityGroups) | @@ -52,27 +51,28 @@ By integrating with Microsoft Entra ID for secure identity management and utiliz | `Microsoft.Network/privateDnsZones/SRV` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/SRV) | | `Microsoft.Network/privateDnsZones/TXT` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/TXT) | | `Microsoft.Network/privateDnsZones/virtualNetworkLinks` | [2020-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-06-01/privateDnsZones/virtualNetworkLinks) | -| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | | `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | | `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | | `Microsoft.OperationalInsights/workspaces` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2023-09-01/workspaces) | | `Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.RecoveryServices/2023-01-01/vaults/backupFabrics/protectionContainers/protectedItems) | | `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | | `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | | `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | | `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | -| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | | `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | -| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | | `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | -| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | ## Usage examples @@ -117,7 +117,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -142,6 +142,25 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param virtualMachineConfiguration = { + adminPassword: '' + adminUsername: 'localAdminUser' +} +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -185,10 +204,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { logAnalyticsConfiguration: { name: 'log-aipbmax' } - managedIdentityConfiguration: { - hubName: 'id-hub-aipbmax' - projectName: 'id-project-aipbmax' - } + managedIdentityName: '' storageAccountConfiguration: { allowSharedKeyAccess: true name: 'staipbmax' @@ -272,7 +288,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -321,11 +337,8 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { "name": "log-aipbmax" } }, - "managedIdentityConfiguration": { - "value": { - "hubName": "id-hub-aipbmax", - "projectName": "id-project-aipbmax" - } + "managedIdentityName": { + "value": "" }, "storageAccountConfiguration": { "value": { @@ -416,6 +429,123 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = 'aipbmax' +// Non-required parameters +param applicationInsightsConfiguration = { + name: 'appi-aipbmax' +} +param bastionConfiguration = { + disableCopyPaste: true + enabled: true + enableFileCopy: true + enableIpConnect: true + enableKerberos: true + enableShareableLink: true + name: 'bas-aipbmax' + networkSecurityGroupResourceId: '' + scaleUnits: 3 + sku: 'Standard' + subnetAddressPrefix: '10.1.1.0/26' +} +param containerRegistryConfiguration = { + name: 'craipbmax' + trustPolicyStatus: 'disabled' +} +param keyVaultConfiguration = { + enablePurgeProtection: false + name: '' +} +param logAnalyticsConfiguration = { + name: 'log-aipbmax' +} +param managedIdentityName = '' +param storageAccountConfiguration = { + allowSharedKeyAccess: true + name: 'staipbmax' + sku: 'Standard_GRS' +} +param virtualMachineConfiguration = { + adminPassword: '' + adminUsername: 'localAdminUser' + enableAadLoginExtension: true + enableAzureMonitorAgent: true + enabled: true + encryptionAtHost: false + imageReference: { + offer: 'dsvm-win-2022' + publisher: 'microsoft-dsvm' + sku: 'winserver-2022' + version: 'latest' + } + maintenanceConfigurationResourceId: '' + name: '' + nicConfigurationConfiguration: { + ipConfigName: 'ipcfg-aipbmax' + name: 'nic-aipbmax' + networkSecurityGroupResourceId: '' + privateIPAllocationMethod: 'Dynamic' + } + osDisk: { + caching: 'ReadOnly' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 256 + managedDisk: { + storageAccountType: 'Standard_LRS' + } + name: 'disk-aipbmax' + } + patchMode: 'AutomaticByPlatform' + size: 'Standard_DS1_v2' + zone: 0 +} +param virtualNetworkConfiguration = { + addressPrefix: '10.1.0.0/16' + enabled: true + name: 'vnet-aipbmax' + subnet: { + addressPrefix: '10.1.0.0/24' + name: 'snet-aipbmax' + networkSecurityGroupResourceId: '' + } +} +param workspaceConfiguration = { + computes: [ + { + computeType: 'ComputeInstance' + description: 'Default' + location: '' + name: '' + properties: { + vmSize: 'STANDARD_DS11_V2' + } + sku: 'Standard' + } + ] + name: 'hub-aipbmax' + networkIsolationMode: 'AllowOnlyApprovedOutbound' + networkOutboundRules: { + rule1: { + category: 'UserDefined' + destination: 'pypi.org' + type: 'FQDN' + } + } + projectName: 'project-aipbmax' +} +``` + +
+

+ ### Example 3: _Without virtual machine_ This instance deploys the module with a virtual network, but no virtual machine or Azure Bastion host. @@ -447,7 +577,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -476,6 +606,27 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param bastionConfiguration = { + enabled: false +} +param virtualMachineConfiguration = { + enabled: false +} +``` + +
+

+ ### Example 4: _Without virtual network_ This instance deploys the module without a virtual network, virtual machine or Azure Bastion host. @@ -504,7 +655,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -528,6 +679,24 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param virtualNetworkConfiguration = { + enabled: false +} +``` + +
+

+ ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -544,6 +713,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { // Required parameters name: '' // Non-required parameters + managedIdentityName: '' tags: { Env: 'test' 'hidden-title': 'This is visible in the resource name' @@ -579,7 +749,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -591,6 +761,9 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { "value": "" }, // Non-required parameters + "managedIdentityName": { + "value": "" + }, "tags": { "value": { "Env": "test", @@ -630,6 +803,48 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/ai-platform/baseline:' + +// Required parameters +param name = '' +// Non-required parameters +param managedIdentityName = '' +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param virtualMachineConfiguration = { + adminPassword: '' + adminUsername: 'localAdminUser' + enableAadLoginExtension: true + enableAzureMonitorAgent: true + maintenanceConfigurationResourceId: '' + patchMode: 'AutomaticByPlatform' + zone: 1 +} +param workspaceConfiguration = { + networkIsolationMode: 'AllowOnlyApprovedOutbound' + networkOutboundRules: { + rule: { + category: 'UserDefined' + destination: { + serviceResourceId: '' + subresourceTarget: 'blob' + } + type: 'PrivateEndpoint' + } + } +} +``` + +
+

+ ## Parameters **Required parameters** @@ -649,7 +864,7 @@ module baseline 'br/public:avm/ptn/ai-platform/baseline:' = { | [`keyVaultConfiguration`](#parameter-keyvaultconfiguration) | object | Configuration for the key vault. | | [`location`](#parameter-location) | string | Location for all Resources. | | [`logAnalyticsConfiguration`](#parameter-loganalyticsconfiguration) | object | Configuration for the Log Analytics workspace. | -| [`managedIdentityConfiguration`](#parameter-managedidentityconfiguration) | object | Configuration for the user-assigned managed identities. | +| [`managedIdentityName`](#parameter-managedidentityname) | string | The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity. | | [`storageAccountConfiguration`](#parameter-storageaccountconfiguration) | object | Configuration for the storage account. | | [`tags`](#parameter-tags) | object | Resource tags. | | [`virtualMachineConfiguration`](#parameter-virtualmachineconfiguration) | secureObject | Configuration for the virtual machine. | @@ -889,30 +1104,9 @@ The name of the Log Analytics workspace. - Required: No - Type: string -### Parameter: `managedIdentityConfiguration` - -Configuration for the user-assigned managed identities. - -- Required: No -- Type: object - -**Optional parameters** - -| Parameter | Type | Description | -| :-- | :-- | :-- | -| [`hubName`](#parameter-managedidentityconfigurationhubname) | string | The name of the workspace hub user-assigned managed identity. | -| [`projectName`](#parameter-managedidentityconfigurationprojectname) | string | The name of the workspace project user-assigned managed identity. | - -### Parameter: `managedIdentityConfiguration.hubName` - -The name of the workspace hub user-assigned managed identity. - -- Required: No -- Type: string - -### Parameter: `managedIdentityConfiguration.projectName` +### Parameter: `managedIdentityName` -The name of the workspace project user-assigned managed identity. +The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity. - Required: No - Type: string @@ -1144,14 +1338,6 @@ The name of the AI Studio workspace project. | `location` | string | The location the module was deployed to. | | `logAnalyticsWorkspaceName` | string | The name of the log analytics workspace. | | `logAnalyticsWorkspaceResourceId` | string | The resource ID of the log analytics workspace. | -| `managedIdentityHubClientId` | string | The client ID of the workspace hub user assigned managed identity. | -| `managedIdentityHubName` | string | The name of the workspace hub user assigned managed identity. | -| `managedIdentityHubPrincipalId` | string | The principal ID of the workspace hub user assigned managed identity. | -| `managedIdentityHubResourceId` | string | The resource ID of the workspace hub user assigned managed identity. | -| `managedIdentityProjectClientId` | string | The client ID of the workspace project user assigned managed identity. | -| `managedIdentityProjectName` | string | The name of the workspace project user assigned managed identity. | -| `managedIdentityProjectPrincipalId` | string | The principal ID of the workspace project user assigned managed identity. | -| `managedIdentityProjectResourceId` | string | The resource ID of the workspace project user assigned managed identity. | | `resourceGroupName` | string | The name of the resource group the module was deployed to. | | `storageAccountName` | string | The name of the storage account. | | `storageAccountResourceId` | string | The resource ID of the storage account. | @@ -1161,8 +1347,10 @@ The name of the AI Studio workspace project. | `virtualNetworkResourceId` | string | The resource ID of the virtual network. | | `virtualNetworkSubnetName` | string | The name of the subnet in the virtual network. | | `virtualNetworkSubnetResourceId` | string | The resource ID of the subnet in the virtual network. | +| `workspaceHubManagedIdentityPrincipalId` | string | The principal ID of the workspace hub system assigned identity, if applicable. | | `workspaceHubName` | string | The name of the workspace hub. | | `workspaceHubResourceId` | string | The resource ID of the workspace hub. | +| `workspaceProjectManagedIdentityPrincipalId` | string | The principal ID of the workspace project system assigned identity. | | `workspaceProjectName` | string | The name of the workspace project. | | `workspaceProjectResourceId` | string | The resource ID of the workspace project. | @@ -1180,6 +1368,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | `br/public:avm/res/network/bastion-host:0.2.2` | Remote reference | | `br/public:avm/res/network/network-security-group:0.3.1` | Remote reference | | `br/public:avm/res/network/private-dns-zone:0.3.1` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | | `br/public:avm/res/storage/storage-account:0.11.0` | Remote reference | ## Data Collection diff --git a/avm/ptn/ai-platform/baseline/main.bicep b/avm/ptn/ai-platform/baseline/main.bicep index d3095c0f79..cfa8b0f7d7 100644 --- a/avm/ptn/ai-platform/baseline/main.bicep +++ b/avm/ptn/ai-platform/baseline/main.bicep @@ -17,8 +17,8 @@ param tags object? @description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true -@description('Optional. Configuration for the user-assigned managed identities.') -param managedIdentityConfiguration managedIdentityConfigurationType +@description('Optional. The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity.') +param managedIdentityName string? @description('Optional. Configuration for the Log Analytics workspace.') param logAnalyticsConfiguration logAnalyticsConfigurationType @@ -59,7 +59,7 @@ var createVirtualMachine = createVirtualNetwork && virtualMachineConfiguration.? var createDefaultNsg = virtualNetworkConfiguration.?subnet.networkSecurityGroupResourceId == null -var subnetResourceId = createVirtualNetwork ? virtualNetwork::defaultSubnet.id : null +var subnetResourceId = createVirtualNetwork ? virtualNetwork.outputs.subnetResourceIds[0] : null var mlTargetSubResource = 'amlworkspace' @@ -103,7 +103,7 @@ module storageAccount_privateDnsZones 'br/public:avm/res/network/private-dns-zon name: zone virtualNetworkLinks: [ { - virtualNetworkResourceId: virtualNetwork.id + virtualNetworkResourceId: virtualNetwork.outputs.resourceId } ] } @@ -117,16 +117,18 @@ module workspaceHub_privateDnsZones 'br/public:avm/res/network/private-dns-zone: name: zone virtualNetworkLinks: [ { - virtualNetworkResourceId: virtualNetwork.id - } - ] - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' + virtualNetworkResourceId: virtualNetwork.outputs.resourceId } ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null } } ] @@ -158,47 +160,37 @@ module defaultNetworkSecurityGroup 'br/public:avm/res/network/network-security-g } } -// Not using the br/public:avm/res/network/virtual-network module here to -// allow consumers of the module to add subnets from outside of the module -// https://github.com/Azure/bicep-registry-modules/issues/2689 -resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = if (createVirtualNetwork) { - name: virtualNetworkConfiguration.?name ?? 'vnet-${name}' - location: location - tags: tags - properties: { - addressSpace: { - addressPrefixes: [ - virtualNetworkConfiguration.?addressPrefix ?? '10.0.0.0/16' - ] - } - } - - resource defaultSubnet 'subnets@2024-01-01' = { - name: virtualNetworkConfiguration.?subnet.name ?? 'default' - properties: { - addressPrefix: virtualNetworkConfiguration.?subnet.addressPrefix ?? '10.0.0.0/24' - networkSecurityGroup: { - id: createDefaultNsg - ? defaultNetworkSecurityGroup.outputs.resourceId - : virtualNetworkConfiguration.?subnet.networkSecurityGroupResourceId - } - } - } - - resource bastionSubnet 'subnets@2024-01-01' = if (createBastion) { - name: 'AzureBastionSubnet' - properties: { - addressPrefix: bastionConfiguration.?subnetAddressPrefix ?? '10.0.1.0/26' - networkSecurityGroup: bastionConfiguration.?networkSecurityGroupResourceId != null - ? { - id: bastionConfiguration.?networkSecurityGroupResourceId - } - : null - } - - dependsOn: [ - defaultSubnet +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.4.0' = if (createVirtualNetwork) { + name: '${uniqueString(deployment().name, location)}-virtual-network' + params: { + name: virtualNetworkConfiguration.?name ?? 'vnet-${name}' + location: location + enableTelemetry: enableTelemetry + addressPrefixes: [ + virtualNetworkConfiguration.?addressPrefix ?? '10.0.0.0/16' ] + subnets: union( + // The default subnet **must** be the first in the subnets array + [ + { + addressPrefix: virtualNetworkConfiguration.?subnet.addressPrefix ?? '10.0.0.0/24' + name: virtualNetworkConfiguration.?subnet.name ?? 'default' + networkSecurityGroupResourceId: createDefaultNsg + ? defaultNetworkSecurityGroup.outputs.resourceId + : virtualNetworkConfiguration.?subnet.networkSecurityGroupResourceId + } + ], + createBastion + ? [ + { + addressPrefix: bastionConfiguration.?subnetAddressPrefix ?? '10.0.1.0/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: bastionConfiguration.?networkSecurityGroupResourceId + } + ] + : [] + ) + tags: tags } } @@ -209,7 +201,7 @@ module bastion 'br/public:avm/res/network/bastion-host:0.2.2' = if (createBastio location: location skuName: bastionConfiguration.?sku ?? 'Standard' enableTelemetry: enableTelemetry - virtualNetworkResourceId: virtualNetwork.id + virtualNetworkResourceId: virtualNetwork.outputs.resourceId disableCopyPaste: bastionConfiguration.?disableCopyPaste enableFileCopy: bastionConfiguration.?enableFileCopy enableIpConnect: bastionConfiguration.?enableIpConnect @@ -238,7 +230,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.5.3' = if (cr { name: virtualMachineConfiguration.?nicConfigurationConfiguration.ipConfigName ?? 'nic-vm-${name}-ipconfig' privateIPAllocationMethod: virtualMachineConfiguration.?nicConfigurationConfiguration.privateIPAllocationMethod ?? 'Dynamic' - subnetResourceId: virtualNetwork::defaultSubnet.id + subnetResourceId: virtualNetwork.outputs.subnetResourceIds[0] } ] } @@ -278,16 +270,8 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.5.3' = if (cr } } -resource managedIdentityHub 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: managedIdentityConfiguration.?hubName ?? 'id-hub-${name}' - location: location - tags: tags -} - -resource managedIdentityProject 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: managedIdentityConfiguration.?projectName ?? 'id-project-${name}' - location: location - tags: tags +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (managedIdentityName != null) { + name: managedIdentityName ?? 'null' } resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { @@ -296,14 +280,14 @@ resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09 tags: tags } -resource resourceGroup_roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { +resource resourceGroup_roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (managedIdentityName != null) { name: guid(resourceGroup().id, name) properties: { roleDefinitionId: subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader ) - principalId: managedIdentityHub.properties.principalId + principalId: userAssignedIdentity.properties.principalId principalType: 'ServicePrincipal' } } @@ -324,28 +308,20 @@ module keyVault 'br/public:avm/res/key-vault/vault:0.6.2' = { } publicNetworkAccess: 'Disabled' enablePurgeProtection: keyVaultConfiguration.?enablePurgeProtection ?? true - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Key Vault Administrator' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Key Vault Administrator' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Key Vault Administrator' + principalType: 'ServicePrincipal' + } + ] + : null diagnosticSettings: [ { workspaceResourceId: logAnalyticsWorkspace.id @@ -385,48 +361,25 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.11.0' = { privateDnsZoneResourceIds: [resourceId('Microsoft.Network/privateDnsZones', zone.key)] }) : null - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Reader' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Storage Account Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Storage Table Data Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Storage Blob Data Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Privileged Contributor - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Privileged Contributor - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Privileged Contributor + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } @@ -444,28 +397,20 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.3.1' = networkRuleBypassOptions: 'AzureServices' zoneRedundancy: 'Enabled' trustPolicyStatus: containerRegistryConfiguration.?trustPolicyStatus ?? 'enabled' - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'AcrPull' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'AcrPull' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'AcrPull' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } } @@ -478,18 +423,15 @@ module applicationInsights 'br/public:avm/res/insights/component:0.3.1' = { kind: 'web' enableTelemetry: enableTelemetry workspaceResourceId: logAnalyticsWorkspace.id - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } } @@ -509,12 +451,14 @@ module workspaceHub 'br/public:avm/res/machine-learning-services/workspace:0.5.0 workspaceHubConfig: { defaultWorkspaceResourceGroup: resourceGroup().id } - managedIdentities: { - userAssignedResourceIds: [ - managedIdentityHub.id - ] - } - primaryUserAssignedIdentity: managedIdentityHub.id + managedIdentities: managedIdentityName != null + ? { + userAssignedResourceIds: [ + userAssignedIdentity.id + ] + } + : null + primaryUserAssignedIdentity: managedIdentityName != null ? userAssignedIdentity.id : null computes: workspaceConfiguration.?computes managedNetworkSettings: { isolationMode: workspaceConfiguration.?networkIsolationMode ?? 'AllowInternetOutbound' @@ -537,19 +481,22 @@ module workspaceHub 'br/public:avm/res/machine-learning-services/workspace:0.5.0 ] : null systemDatastoresAuthMode: 'identity' - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } dependsOn: workspaceHub_privateDnsZones } +// The workspace project uses a system assigned managed identity, so it can authenticate with the container registry module workspaceProject 'br/public:avm/res/machine-learning-services/workspace:0.5.0' = { name: '${uniqueString(deployment().name, location)}-project' params: { @@ -559,24 +506,15 @@ module workspaceProject 'br/public:avm/res/machine-learning-services/workspace:0 enableTelemetry: enableTelemetry kind: 'Project' hubResourceId: workspaceHub.outputs.resourceId - managedIdentities: { - userAssignedResourceIds: [ - managedIdentityProject.id - ] - } - primaryUserAssignedIdentity: managedIdentityProject.id - roleAssignments: [ - { - principalId: managedIdentityHub.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - { - principalId: managedIdentityProject.properties.principalId - roleDefinitionIdOrName: 'Contributor' - principalType: 'ServicePrincipal' - } - ] + roleAssignments: managedIdentityName != null + ? [ + { + principalId: userAssignedIdentity.properties.principalId + roleDefinitionIdOrName: 'Contributor' + principalType: 'ServicePrincipal' + } + ] + : null tags: tags } } @@ -612,30 +550,6 @@ output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.id @description('The name of the log analytics workspace.') output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name -@description('The resource ID of the workspace hub user assigned managed identity.') -output managedIdentityHubResourceId string = managedIdentityHub.id - -@description('The name of the workspace hub user assigned managed identity.') -output managedIdentityHubName string = managedIdentityHub.name - -@description('The principal ID of the workspace hub user assigned managed identity.') -output managedIdentityHubPrincipalId string = managedIdentityHub.properties.principalId - -@description('The client ID of the workspace hub user assigned managed identity.') -output managedIdentityHubClientId string = managedIdentityHub.properties.clientId - -@description('The resource ID of the workspace project user assigned managed identity.') -output managedIdentityProjectResourceId string = managedIdentityProject.id - -@description('The name of the workspace project user assigned managed identity.') -output managedIdentityProjectName string = managedIdentityProject.name - -@description('The principal ID of the workspace project user assigned managed identity.') -output managedIdentityProjectPrincipalId string = managedIdentityProject.properties.principalId - -@description('The client ID of the workspace project user assigned managed identity.') -output managedIdentityProjectClientId string = managedIdentityProject.properties.clientId - @description('The resource ID of the key vault.') output keyVaultResourceId string = keyVault.outputs.resourceId @@ -663,6 +577,12 @@ output workspaceHubResourceId string = workspaceHub.outputs.resourceId @description('The name of the workspace hub.') output workspaceHubName string = workspaceHub.outputs.name +@description('The principal ID of the workspace hub system assigned identity, if applicable.') +output workspaceHubManagedIdentityPrincipalId string = workspaceHub.outputs.systemAssignedMIPrincipalId + +@description('The principal ID of the workspace project system assigned identity.') +output workspaceProjectManagedIdentityPrincipalId string = workspaceProject.outputs.systemAssignedMIPrincipalId + @description('The resource ID of the workspace project.') output workspaceProjectResourceId string = workspaceProject.outputs.resourceId @@ -670,16 +590,16 @@ output workspaceProjectResourceId string = workspaceProject.outputs.resourceId output workspaceProjectName string = workspaceProject.outputs.name @description('The resource ID of the virtual network.') -output virtualNetworkResourceId string = createVirtualNetwork ? virtualNetwork.id : '' +output virtualNetworkResourceId string = createVirtualNetwork ? virtualNetwork.outputs.resourceId : '' @description('The name of the virtual network.') -output virtualNetworkName string = createVirtualNetwork ? virtualNetwork.name : '' +output virtualNetworkName string = createVirtualNetwork ? virtualNetwork.outputs.name : '' @description('The resource ID of the subnet in the virtual network.') -output virtualNetworkSubnetResourceId string = createVirtualNetwork ? virtualNetwork::defaultSubnet.id : '' +output virtualNetworkSubnetResourceId string = createVirtualNetwork ? virtualNetwork.outputs.subnetResourceIds[0] : '' @description('The name of the subnet in the virtual network.') -output virtualNetworkSubnetName string = createVirtualNetwork ? virtualNetwork::defaultSubnet.name : '' +output virtualNetworkSubnetName string = createVirtualNetwork ? virtualNetwork.outputs.subnetNames[0] : '' @description('The resource ID of the Azure Bastion host.') output bastionResourceId string = createBastion ? bastion.outputs.resourceId : '' @@ -697,14 +617,6 @@ output virtualMachineName string = createVirtualMachine ? virtualMachine.outputs // Definitions // // ================ // -type managedIdentityConfigurationType = { - @description('Optional. The name of the workspace hub user-assigned managed identity.') - hubName: string? - - @description('Optional. The name of the workspace project user-assigned managed identity.') - projectName: string? -}? - type logAnalyticsConfigurationType = { @description('Optional. The name of the Log Analytics workspace.') name: string? diff --git a/avm/ptn/ai-platform/baseline/main.json b/avm/ptn/ai-platform/baseline/main.json index 4fe65a2d83..cbb20a89d4 100644 --- a/avm/ptn/ai-platform/baseline/main.json +++ b/avm/ptn/ai-platform/baseline/main.json @@ -5,34 +5,14 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2263138345896714301" + "version": "0.30.23.60470", + "templateHash": "14190804454906731332" }, "name": "AI Platform Baseline", "description": "This module provides a secure and scalable environment for deploying AI applications on Azure.\nThe module encompasses all essential components required for building, managing, and observing AI solutions, including a machine learning workspace, observability tools, and necessary data management services.\nBy integrating with Microsoft Entra ID for secure identity management and utilizing private endpoints for services like Key Vault and Blob Storage, the module ensures secure communication and data access.", "owner": "Azure/module-maintainers" }, "definitions": { - "managedIdentityConfigurationType": { - "type": "object", - "properties": { - "hubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the workspace hub user-assigned managed identity." - } - }, - "projectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the workspace project user-assigned managed identity." - } - } - }, - "nullable": true - }, "logAnalyticsConfigurationType": { "type": "object", "properties": { @@ -776,10 +756,11 @@ "description": "Optional. Enable/Disable usage telemetry for module." } }, - "managedIdentityConfiguration": { - "$ref": "#/definitions/managedIdentityConfigurationType", + "managedIdentityName": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. Configuration for the user-assigned managed identities." + "description": "Optional. The name of the user assigned identity for the AI Studio hub. If not provided, the hub will use a system assigned identity." } }, "logAnalyticsConfiguration": { @@ -842,7 +823,6 @@ "createBastion": "[and(variables('createVirtualNetwork'), not(equals(tryGet(parameters('bastionConfiguration'), 'enabled'), false())))]", "createVirtualMachine": "[and(variables('createVirtualNetwork'), not(equals(tryGet(parameters('virtualMachineConfiguration'), 'enabled'), false())))]", "createDefaultNsg": "[equals(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'networkSecurityGroupResourceId'), null())]", - "subnetResourceId": "[if(variables('createVirtualNetwork'), resourceId('Microsoft.Network/virtualNetworks/subnets', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default')), null())]", "mlTargetSubResource": "amlworkspace", "mlPrivateDnsZones": { "privatelink.api.azureml.ms": "[variables('mlTargetSubResource')]", @@ -854,36 +834,6 @@ } }, "resources": { - "virtualNetwork::defaultSubnet": { - "condition": "[variables('createVirtualNetwork')]", - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'))]", - "properties": { - "addressPrefix": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'addressPrefix'), '10.0.0.0/24')]", - "networkSecurityGroup": { - "id": "[if(variables('createDefaultNsg'), reference('defaultNetworkSecurityGroup').outputs.resourceId.value, tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'networkSecurityGroupResourceId'))]" - } - }, - "dependsOn": [ - "defaultNetworkSecurityGroup", - "virtualNetwork" - ] - }, - "virtualNetwork::bastionSubnet": { - "condition": "[and(variables('createVirtualNetwork'), variables('createBastion'))]", - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), 'AzureBastionSubnet')]", - "properties": { - "addressPrefix": "[coalesce(tryGet(parameters('bastionConfiguration'), 'subnetAddressPrefix'), '10.0.1.0/26')]", - "networkSecurityGroup": "[if(not(equals(tryGet(parameters('bastionConfiguration'), 'networkSecurityGroupResourceId'), null())), createObject('id', tryGet(parameters('bastionConfiguration'), 'networkSecurityGroupResourceId')), null())]" - }, - "dependsOn": [ - "virtualNetwork::defaultSubnet", - "virtualNetwork" - ] - }, "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", @@ -904,34 +854,12 @@ } } }, - "virtualNetwork": { - "condition": "[variables('createVirtualNetwork')]", - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'addressPrefix'), '10.0.0.0/16')]" - ] - } - } - }, - "managedIdentityHub": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "managedIdentityProject": { + "userAssignedIdentity": { + "condition": "[not(equals(parameters('managedIdentityName'), null()))]", + "existing": true, "type": "Microsoft.ManagedIdentity/userAssignedIdentities", "apiVersion": "2023-01-31", - "name": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name')))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" + "name": "[coalesce(parameters('managedIdentityName'), 'null')]" }, "logAnalyticsWorkspace": { "type": "Microsoft.OperationalInsights/workspaces", @@ -941,16 +869,17 @@ "tags": "[parameters('tags')]" }, "resourceGroup_roleAssignment": { + "condition": "[not(equals(parameters('managedIdentityName'), null()))]", "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "name": "[guid(resourceGroup().id, parameters('name'))]", "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "principalId": "[reference('managedIdentityHub').principalId]", + "principalId": "[reference('userAssignedIdentity').principalId]", "principalType": "ServicePrincipal" }, "dependsOn": [ - "managedIdentityHub" + "userAssignedIdentity" ] }, "storageAccount_privateDnsZones": { @@ -974,7 +903,7 @@ "virtualNetworkLinks": { "value": [ { - "virtualNetworkResourceId": "[resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))))]" + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" } ] } @@ -3856,19 +3785,11 @@ "virtualNetworkLinks": { "value": [ { - "virtualNetworkResourceId": "[resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))))]" + "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" } ] }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - } + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -6723,7 +6644,7 @@ } }, "dependsOn": [ - "managedIdentityHub", + "userAssignedIdentity", "virtualNetwork" ] }, @@ -7291,38 +7212,1555 @@ "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" } } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkSecurityGroups', 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": [ + "networkSecurityGroup" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network security group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the network security group." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the network security group." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + } + } + } + } + }, + "virtualNetwork": { + "condition": "[variables('createVirtualNetwork')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtual-network', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name')))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "addressPrefixes": { + "value": [ + "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'addressPrefix'), '10.0.0.0/16')]" + ] + }, + "subnets": { + "value": "[union(createArray(createObject('addressPrefix', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'addressPrefix'), '10.0.0.0/24'), 'name', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'), 'networkSecurityGroupResourceId', if(variables('createDefaultNsg'), reference('defaultNetworkSecurityGroup').outputs.resourceId.value, tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'networkSecurityGroupResourceId')))), if(variables('createBastion'), createArray(createObject('addressPrefix', coalesce(tryGet(parameters('bastionConfiguration'), 'subnetAddressPrefix'), '10.0.1.0/26'), 'name', 'AzureBastionSubnet', 'networkSecurityGroupResourceId', tryGet(parameters('bastionConfiguration'), 'networkSecurityGroupResourceId'))), createArray()))]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "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.29.47.4906", + "templateHash": "15949466154563447171" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "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." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": { + "addressPrefixes": "[parameters('addressPrefixes')]" + }, + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" + } + }, + "virtualNetwork_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/virtualNetworks/{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": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + } + }, + "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.29.47.4906", + "templateHash": "5699372618313647761" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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", + "metadata": { + "description": "Requird. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } }, "dependsOn": [ - "networkSecurityGroup" + "virtualNetwork" ] }, - "networkSecurityGroup_roleAssignments": { + "virtualNetwork_peering_remote": { "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkSecurityGroups', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", "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')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } }, "dependsOn": [ - "networkSecurityGroup" + "virtualNetwork" ] } }, @@ -7330,34 +8768,57 @@ "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the network security group was deployed into." + "description": "The resource group the virtual network was deployed into." }, "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the network security group." + "description": "The resource ID of the virtual network." }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" }, "name": { "type": "string", "metadata": { - "description": "The name of the network security group." + "description": "The name of the virtual network." }, "value": "[parameters('name')]" }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } - } + }, + "dependsOn": [ + "defaultNetworkSecurityGroup" + ] }, "bastion": { "condition": "[variables('createBastion')]", @@ -7383,7 +8844,7 @@ "value": "[parameters('enableTelemetry')]" }, "virtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))))]" + "value": "[reference('virtualNetwork').outputs.resourceId.value]" }, "disableCopyPaste": { "value": "[tryGet(parameters('bastionConfiguration'), 'disableCopyPaste')]" @@ -8582,7 +10043,7 @@ { "name": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'nicConfigurationConfiguration', 'ipConfigName'), format('nic-vm-{0}-ipconfig', parameters('name')))]", "privateIPAllocationMethod": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'nicConfigurationConfiguration', 'privateIPAllocationMethod'), 'Dynamic')]", - "subnetResourceId": "[resourceId('Microsoft.Network/virtualNetworks/subnets', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'))]" + "subnetResourceId": "[reference('virtualNetwork').outputs.subnetResourceIds.value[0]]" } ] } @@ -14001,7 +15462,7 @@ } }, "dependsOn": [ - "virtualNetwork::defaultSubnet" + "virtualNetwork" ] }, "keyVault": { @@ -14047,30 +15508,7 @@ "enablePurgeProtection": { "value": "[coalesce(tryGet(parameters('keyVaultConfiguration'), 'enablePurgeProtection'), true())]" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Key Vault Administrator", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Key Vault Administrator", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Key Vault Administrator', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "diagnosticSettings": { "value": [ { @@ -16818,8 +18256,7 @@ }, "dependsOn": [ "logAnalyticsWorkspace", - "managedIdentityHub", - "managedIdentityProject" + "userAssignedIdentity" ] }, "storageAccount": { @@ -16862,51 +18299,8 @@ "bypass": "AzureServices" } }, - "privateEndpoints": "[if(not(equals(variables('subnetResourceId'), null())), createObject('value', map(items(variables('storagePrivateDnsZones')), lambda('zone', createObject('name', format('pep-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'service', lambdaVariables('zone').value, 'subnetResourceId', coalesce(variables('subnetResourceId'), ''), 'privateDnsZoneResourceIds', createArray(resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone').key)))))), createObject('value', null()))]", - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Reader", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Storage Account Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Storage Table Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Storage Blob Data Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "69566ab7-960f-475b-8e7c-b3118f30c6bd", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "69566ab7-960f-475b-8e7c-b3118f30c6bd", - "principalType": "ServicePrincipal" - } - ] - }, + "privateEndpoints": "[if(not(equals(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), null())), createObject('value', map(items(variables('storagePrivateDnsZones')), lambda('zone', createObject('name', format('pep-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', lambdaVariables('zone').value, parameters('name')), 'service', lambdaVariables('zone').value, 'subnetResourceId', coalesce(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), ''), 'privateDnsZoneResourceIds', createArray(resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone').key)))))), createObject('value', null()))]", + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Storage Blob Data Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', '69566ab7-960f-475b-8e7c-b3118f30c6bd', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -21569,10 +22963,9 @@ } }, "dependsOn": [ - "virtualNetwork::defaultSubnet", - "managedIdentityHub", - "managedIdentityProject", - "storageAccount_privateDnsZones" + "storageAccount_privateDnsZones", + "userAssignedIdentity", + "virtualNetwork" ] }, "containerRegistry": { @@ -21609,30 +23002,7 @@ "trustPolicyStatus": { "value": "[coalesce(tryGet(parameters('containerRegistryConfiguration'), 'trustPolicyStatus'), 'enabled')]" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "AcrPull", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "AcrPull", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'), createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'AcrPull', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -23754,8 +25124,7 @@ } }, "dependsOn": [ - "managedIdentityHub", - "managedIdentityProject" + "userAssignedIdentity" ] }, "applicationInsights": { @@ -23783,20 +25152,7 @@ "workspaceResourceId": { "value": "[resourceId('Microsoft.OperationalInsights/workspaces', coalesce(tryGet(parameters('logAnalyticsConfiguration'), 'name'), format('log-{0}', parameters('name'))))]" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -24397,8 +25753,7 @@ }, "dependsOn": [ "logAnalyticsWorkspace", - "managedIdentityHub", - "managedIdentityProject" + "userAssignedIdentity" ] }, "workspaceHub": { @@ -24443,16 +25798,8 @@ "defaultWorkspaceResourceGroup": "[resourceGroup().id]" } }, - "managedIdentities": { - "value": { - "userAssignedResourceIds": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name'))))]" - ] - } - }, - "primaryUserAssignedIdentity": { - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name'))))]" - }, + "managedIdentities": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createObject('userAssignedResourceIds', createArray(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(parameters('managedIdentityName'), 'null'))))), createObject('value', null()))]", + "primaryUserAssignedIdentity": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(parameters('managedIdentityName'), 'null'))), createObject('value', null()))]", "computes": { "value": "[tryGet(parameters('workspaceConfiguration'), 'computes')]" }, @@ -24462,19 +25809,11 @@ "outboundRules": "[tryGet(parameters('workspaceConfiguration'), 'networkOutboundRules')]" } }, - "privateEndpoints": "[if(not(equals(variables('subnetResourceId'), null())), createObject('value', createArray(createObject('name', format('pep-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'service', variables('mlTargetSubResource'), 'subnetResourceId', coalesce(variables('subnetResourceId'), ''), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', map(objectKeys(variables('mlPrivateDnsZones')), lambda('zone', createObject('name', replace(lambdaVariables('zone'), '.', '-'), 'privateDnsZoneResourceId', resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone'))))))))), createObject('value', null()))]", + "privateEndpoints": "[if(not(equals(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), null())), createObject('value', createArray(createObject('name', format('pep-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'customNetworkInterfaceName', format('nic-{0}-{1}', variables('mlTargetSubResource'), parameters('name')), 'service', variables('mlTargetSubResource'), 'subnetResourceId', coalesce(if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], null()), ''), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', map(objectKeys(variables('mlPrivateDnsZones')), lambda('zone', createObject('name', replace(lambdaVariables('zone'), '.', '-'), 'privateDnsZoneResourceId', resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone'))))))))), createObject('value', null()))]", "systemDatastoresAuthMode": { "value": "identity" }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -26718,10 +28057,10 @@ "dependsOn": [ "applicationInsights", "containerRegistry", - "virtualNetwork::defaultSubnet", "keyVault", - "managedIdentityHub", "storageAccount", + "userAssignedIdentity", + "virtualNetwork", "workspaceHub_privateDnsZones" ] }, @@ -26753,30 +28092,7 @@ "hubResourceId": { "value": "[reference('workspaceHub').outputs.resourceId.value]" }, - "managedIdentities": { - "value": { - "userAssignedResourceIds": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name'))))]" - ] - } - }, - "primaryUserAssignedIdentity": { - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name'))))]" - }, - "roleAssignments": { - "value": [ - { - "principalId": "[reference('managedIdentityHub').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - }, - { - "principalId": "[reference('managedIdentityProject').principalId]", - "roleDefinitionIdOrName": "Contributor", - "principalType": "ServicePrincipal" - } - ] - }, + "roleAssignments": "[if(not(equals(parameters('managedIdentityName'), null())), createObject('value', createArray(createObject('principalId', reference('userAssignedIdentity').principalId, 'roleDefinitionIdOrName', 'Contributor', 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", "tags": { "value": "[parameters('tags')]" } @@ -29018,8 +30334,7 @@ } }, "dependsOn": [ - "managedIdentityHub", - "managedIdentityProject", + "userAssignedIdentity", "workspaceHub" ] } @@ -29088,62 +30403,6 @@ }, "value": "[coalesce(tryGet(parameters('logAnalyticsConfiguration'), 'name'), format('log-{0}', parameters('name')))]" }, - "managedIdentityHubResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the workspace hub user assigned managed identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name'))))]" - }, - "managedIdentityHubName": { - "type": "string", - "metadata": { - "description": "The name of the workspace hub user assigned managed identity." - }, - "value": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'hubName'), format('id-hub-{0}', parameters('name')))]" - }, - "managedIdentityHubPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the workspace hub user assigned managed identity." - }, - "value": "[reference('managedIdentityHub').principalId]" - }, - "managedIdentityHubClientId": { - "type": "string", - "metadata": { - "description": "The client ID of the workspace hub user assigned managed identity." - }, - "value": "[reference('managedIdentityHub').clientId]" - }, - "managedIdentityProjectResourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the workspace project user assigned managed identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name'))))]" - }, - "managedIdentityProjectName": { - "type": "string", - "metadata": { - "description": "The name of the workspace project user assigned managed identity." - }, - "value": "[coalesce(tryGet(parameters('managedIdentityConfiguration'), 'projectName'), format('id-project-{0}', parameters('name')))]" - }, - "managedIdentityProjectPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the workspace project user assigned managed identity." - }, - "value": "[reference('managedIdentityProject').principalId]" - }, - "managedIdentityProjectClientId": { - "type": "string", - "metadata": { - "description": "The client ID of the workspace project user assigned managed identity." - }, - "value": "[reference('managedIdentityProject').clientId]" - }, "keyVaultResourceId": { "type": "string", "metadata": { @@ -29207,6 +30466,20 @@ }, "value": "[reference('workspaceHub').outputs.name.value]" }, + "workspaceHubManagedIdentityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the workspace hub system assigned identity, if applicable." + }, + "value": "[reference('workspaceHub').outputs.systemAssignedMIPrincipalId.value]" + }, + "workspaceProjectManagedIdentityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the workspace project system assigned identity." + }, + "value": "[reference('workspaceProject').outputs.systemAssignedMIPrincipalId.value]" + }, "workspaceProjectResourceId": { "type": "string", "metadata": { @@ -29226,28 +30499,28 @@ "metadata": { "description": "The resource ID of the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), resourceId('Microsoft.Network/virtualNetworks', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name')))), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.resourceId.value, '')]" }, "virtualNetworkName": { "type": "string", "metadata": { "description": "The name of the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.name.value, '')]" }, "virtualNetworkSubnetResourceId": { "type": "string", "metadata": { "description": "The resource ID of the subnet in the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), resourceId('Microsoft.Network/virtualNetworks/subnets', coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('name'))), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default')), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetResourceIds.value[0], '')]" }, "virtualNetworkSubnetName": { "type": "string", "metadata": { "description": "The name of the subnet in the virtual network." }, - "value": "[if(variables('createVirtualNetwork'), coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnet', 'name'), 'default'), '')]" + "value": "[if(variables('createVirtualNetwork'), reference('virtualNetwork').outputs.subnetNames.value[0], '')]" }, "bastionResourceId": { "type": "string", diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep index d2ea57bb6a..1ce964acc0 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/max/dependencies.bicep @@ -4,6 +4,9 @@ param location string = resourceGroup().location @description('Required. The name of the Storage Account to create.') param storageAccountName string +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + @description('Required. The name of the Maintenance Configuration to create.') param maintenanceConfigurationName string @@ -13,6 +16,11 @@ param networkSecurityGroupName string @description('Required. The name of the Bastion Network Security Group to create.') param networkSecurityGroupBastionName string +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { name: storageAccountName location: location @@ -196,6 +204,9 @@ resource networkSecurityGroupBastion 'Microsoft.Network/networkSecurityGroups@20 @description('The resource ID of the created Storage Account.') output storageAccountResourceId string = storageAccount.id +@description('The name of the created Managed Identity.') +output managedIdentityName string = managedIdentity.name + @description('The resource ID of the created Network Security Group.') output networkSecurityGroupResourceId string = networkSecurityGroup.id diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep index 240496050a..a8beac49bf 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/max/main.test.bicep @@ -44,6 +44,7 @@ module nestedDependencies 'dependencies.bicep' = { params: { location: resourceLocation storageAccountName: 'dep${namePrefix}st${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' networkSecurityGroupName: 'dep${namePrefix}nsg${serviceShort}' networkSecurityGroupBastionName: 'dep-${namePrefix}-nsg-bastion-${serviceShort}' @@ -61,10 +62,7 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}' - managedIdentityConfiguration: { - hubName: '${namePrefix}-id-hub-${serviceShort}' - projectName: '${namePrefix}-id-project-${serviceShort}' - } + managedIdentityName: nestedDependencies.outputs.managedIdentityName logAnalyticsConfiguration: { name: '${namePrefix}-log-${serviceShort}' } diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep index 299d71ad37..cf931cdcdf 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/dependencies.bicep @@ -1,12 +1,20 @@ @description('Optional. The location to deploy to.') param location string = resourceGroup().location +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + @description('Required. The name of the Maintenance Configuration to create.') param maintenanceConfigurationName string @description('Required. The name of the Storage Account to create.') param storageAccountName string +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { name: storageAccountName location: location @@ -16,6 +24,19 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { kind: 'StorageV2' } +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, storageAccount.id, managedIdentity.id) + scope: storageAccount + properties: { + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b556d68e-0be0-4f35-a333-ad7ee1ce17ea' // Azure AI Enterprise Network Connection Approver + ) + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + resource maintenanceConfiguration 'Microsoft.Maintenance/maintenanceConfigurations@2023-10-01-preview' = { name: maintenanceConfigurationName location: location @@ -46,5 +67,8 @@ resource maintenanceConfiguration 'Microsoft.Maintenance/maintenanceConfiguratio @description('The resource ID of the created Storage Account.') output storageAccountResourceId string = storageAccount.id +@description('The name of the created Managed Identity.') +output managedIdentityName string = managedIdentity.name + @description('The resource ID of the maintenance configuration.') output maintenanceConfigurationResourceId string = maintenanceConfiguration.id diff --git a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep index 21d1ba8934..ec39ff7d58 100644 --- a/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/ptn/ai-platform/baseline/tests/e2e/waf-aligned/main.test.bicep @@ -44,6 +44,7 @@ module nestedDependencies 'dependencies.bicep' = { name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { storageAccountName: 'dep${namePrefix}st${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' location: enforcedLocation } @@ -60,6 +61,7 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + managedIdentityName: nestedDependencies.outputs.managedIdentityName virtualMachineConfiguration: { adminUsername: 'localAdminUser' adminPassword: password diff --git a/avm/ptn/ai-platform/baseline/version.json b/avm/ptn/ai-platform/baseline/version.json index aa34c4d0f5..c332ff1f3a 100644 --- a/avm/ptn/ai-platform/baseline/version.json +++ b/avm/ptn/ai-platform/baseline/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.6", "pathFilters": [ "./main.json" ] diff --git a/avm/ptn/authorization/policy-assignment/README.md b/avm/ptn/authorization/policy-assignment/README.md index a4cb51a7ea..072b3bbe2e 100644 --- a/avm/ptn/authorization/policy-assignment/README.md +++ b/avm/ptn/authorization/policy-assignment/README.md @@ -62,7 +62,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,26 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apamgmin001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +// Non-required parameters +param location = '' +param metadata = { + assignedBy: 'Bicep' +} +``` + +
+

+ ### Example 2: _Policy Assignments (Management Group scope)_ This module deploys a Policy Assignment at a Management Group scope using common parameters. @@ -182,7 +202,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -294,6 +314,86 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apamgmax001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +// Non-required parameters +param description = '[Description] Policy Assignment at the management group scope' +param displayName = '[Display Name] Policy Assignment at the management group scope' +param enforcementMode = 'DoNotEnforce' +param identity = 'SystemAssigned' +param location = '' +param managementGroupId = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param nonComplianceMessages = [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } +] +param notScopes = [ + '/subscriptions//resourceGroups/validation-rg' +] +param overrides = [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } +] +param parameters = { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } +} +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param roleDefinitionIds = [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' +] +``` + +
+

+ ### Example 3: _Policy Assignments (Resource Group)_ This module deploys a Policy Assignment at a Resource Group scope using minimal parameters. @@ -326,7 +426,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -362,6 +462,28 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apargmin001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +// Non-required parameters +param location = '' +param metadata = { + assignedBy: 'Bicep' +} +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ ### Example 4: _Policy Assignments (Resource Group)_ This module deploys a Policy Assignment at a Resource Group scope using common parameters. @@ -454,7 +576,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -572,6 +694,88 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apargmax001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +// Non-required parameters +param description = '[Description] Policy Assignment at the resource group scope' +param displayName = '[Display Name] Policy Assignment at the resource group scope' +param enforcementMode = 'DoNotEnforce' +param identity = 'UserAssigned' +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param nonComplianceMessages = [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } +] +param notScopes = [ + '' +] +param overrides = [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } +] +param parameters = { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } +} +param resourceGroupName = '' +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param roleDefinitionIds = [ + '/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' +] +param subscriptionId = '' +param userAssignedIdentityId = '' +``` + +
+

+ ### Example 5: _Policy Assignments (Subscription)_ This module deploys a Policy Assignment at a Subscription scope using common parameters. @@ -605,7 +809,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -640,6 +844,29 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apasubmin001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' +// Non-required parameters +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param subscriptionId = '' +``` + +
+

+ ### Example 6: _Policy Assignments (Subscription)_ This module deploys a Policy Assignment at a Subscription scope using common parameters. @@ -731,7 +958,7 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment: -

via JSON Parameter file +via JSON parameters file ```json { @@ -846,6 +1073,87 @@ module policyAssignment 'br/public:avm/ptn/authorization/policy-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/policy-assignment:' + +// Required parameters +param name = 'apasubmax001' +param policyDefinitionId = '/providers/Microsoft.Authorization/policySetDefinitions/39a366e6-fdde-4f41-bbf8-3757f46d1611' +// Non-required parameters +param description = '[Description] Policy Assignment at the subscription scope' +param displayName = '[Display Name] Policy Assignment at the subscription scope' +param enforcementMode = 'DoNotEnforce' +param identity = 'UserAssigned' +param location = '' +param metadata = { + assignedBy: 'Bicep' + category: 'Security' + version: '1.0' +} +param nonComplianceMessages = [ + { + message: 'Violated Policy Assignment - This is a Non Compliance Message' + } +] +param notScopes = [ + '/subscriptions//resourceGroups/validation-rg' +] +param overrides = [ + { + kind: 'policyEffect' + selectors: [ + { + in: [ + 'ASC_DeployAzureDefenderForSqlAdvancedThreatProtectionWindowsAgent' + 'ASC_DeployAzureDefenderForSqlVulnerabilityAssessmentWindowsAgent' + ] + kind: 'policyDefinitionReferenceId' + } + ] + value: 'Disabled' + } +] +param parameters = { + effect: { + value: 'Disabled' + } + enableCollectionOfSqlQueriesForSecurityResearch: { + value: false + } +} +param resourceSelectors = [ + { + name: 'resourceSelector-test' + selectors: [ + { + in: [ + 'Microsoft.Compute/virtualMachines' + ] + kind: 'resourceType' + } + { + in: [ + 'westeurope' + ] + kind: 'resourceLocation' + } + ] + } +] +param roleDefinitionIds = [ + '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' +] +param subscriptionId = '' +param userAssignedIdentityId = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/authorization/resource-role-assignment/README.md b/avm/ptn/authorization/resource-role-assignment/README.md index 8326536d6c..4e02efebcd 100644 --- a/avm/ptn/authorization/resource-role-assignment/README.md +++ b/avm/ptn/authorization/resource-role-assignment/README.md @@ -55,7 +55,7 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

-via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,26 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/resource-role-assignment:' + +// Required parameters +param principalId = '' +param resourceId = '' +param roleDefinitionId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +// Non-required parameters +param description = 'Assign Storage Blob Data Reader role to the managed identity on the storage account.' +param principalType = 'ServicePrincipal' +param roleName = 'Storage Blob Data Reader' +``` + +
+

+ ### Example 2: _Resource Role Assignments_ This module deploys a Resource Role Assignment using minimal parameters. @@ -117,7 +137,7 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

-via JSON Parameter file +via JSON parameters file ```json { @@ -145,6 +165,24 @@ module resourceRoleAssignment 'br/public:avm/ptn/authorization/resource-role-ass

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/resource-role-assignment:' + +// Required parameters +param principalId = '' +param resourceId = '' +param roleDefinitionId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' +// Non-required parameters +param principalType = 'ServicePrincipal' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/authorization/role-assignment/README.md b/avm/ptn/authorization/role-assignment/README.md index 99ebde63c1..b5046b581e 100644 --- a/avm/ptn/authorization/role-assignment/README.md +++ b/avm/ptn/authorization/role-assignment/README.md @@ -59,7 +59,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,24 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Resource Policy Contributor' +// Non-required parameters +param location = '' +param principalType = 'ServicePrincipal' +``` + +
+

+ ### Example 2: _Role Assignments (Management Group scope)_ This module deploys a Role Assignment at a Management Group scope using common parameters. @@ -117,7 +135,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -151,6 +169,26 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Management Group Reader' +// Non-required parameters +param description = 'Role Assignment (management group scope)' +param location = '' +param managementGroupId = '' +param principalType = 'ServicePrincipal' +``` + +
+

+ ### Example 3: _Role Assignments (Resource Group scope)_ This module deploys a Role Assignment at a Resource Group scope using minimal parameters. @@ -181,7 +219,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -215,6 +253,26 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' +// Non-required parameters +param location = '' +param principalType = 'ServicePrincipal' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ ### Example 4: _Role Assignments (Resource Group)_ This module deploys a Role Assignment at a Resource Group scope using common parameters. @@ -246,7 +304,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -283,6 +341,27 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Reader' +// Non-required parameters +param description = 'Role Assignment (resource group scope)' +param location = '' +param principalType = 'ServicePrincipal' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
+

+ ### Example 5: _Role Assignments (Subscription scope)_ This module deploys a Role Assignment at a Subscription scope using minimal parameters. @@ -312,7 +391,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -343,6 +422,25 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = '' +// Non-required parameters +param location = '' +param principalType = 'ServicePrincipal' +param subscriptionId = '' +``` + +
+

+ ### Example 6: _Role Assignments (Subscription scope)_ This module deploys a Role Assignment at a Subscription scope using common parameters. @@ -373,7 +471,7 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

-via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +505,26 @@ module roleAssignment 'br/public:avm/ptn/authorization/role-assignment:

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/authorization/role-assignment:' + +// Required parameters +param principalId = '' +param roleDefinitionIdOrName = 'Reader' +// Non-required parameters +param description = 'Role Assignment (subscription scope)' +param location = '' +param principalType = 'ServicePrincipal' +param subscriptionId = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/azd/apim-api/README.md b/avm/ptn/azd/apim-api/README.md index 681638af79..a063fabfb7 100644 --- a/avm/ptn/azd/apim-api/README.md +++ b/avm/ptn/azd/apim-api/README.md @@ -10,7 +10,6 @@ Creates and configure an API within an API Management service instance. - [Usage examples](#Usage-examples) - [Parameters](#Parameters) - [Outputs](#Outputs) -- [Cross-referenced modules](#Cross-referenced-modules) - [Data Collection](#Data-Collection) ## Resource Types @@ -64,7 +63,7 @@ module apimApi 'br/public:avm/ptn/azd/apim-api:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -104,6 +103,27 @@ module apimApi 'br/public:avm/ptn/azd/apim-api:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/apim-api:' + +// Required parameters +param apiBackendUrl = '' +param apiDescription = 'api description' +param apiDisplayName = 'apd-aapmin' +param apiName = 'an-aapmin001' +param apiPath = 'apipath-aapmin' +param name = '' +param webFrontendUrl = '' +// Non-required parameters +param location = '' +``` + +
+

## Parameters @@ -117,7 +137,7 @@ module apimApi 'br/public:avm/ptn/azd/apim-api:' = { | [`apiName`](#parameter-apiname) | string | Resource name to uniquely identify this API within the API Management service instance. | | [`apiPath`](#parameter-apipath) | string | Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API. | | [`name`](#parameter-name) | string | Name of the API Management service instance. | -| [`webFrontendUrl`](#parameter-webfrontendurl) | string | Absolute URL of the web frontend. | +| [`webFrontendUrl`](#parameter-webfrontendurl) | string | Absolute URL of web frontend. | **Optional parameters** @@ -171,7 +191,7 @@ Name of the API Management service instance. ### Parameter: `webFrontendUrl` -Absolute URL of the web frontend. +Absolute URL of web frontend. - Required: Yes - Type: string @@ -200,7 +220,6 @@ Location for all Resources. - Type: string - Default: `[resourceGroup().location]` - ## Outputs | Output | Type | Description | @@ -208,10 +227,6 @@ Location for all Resources. | `resourceGroupName` | string | The name of the resource group. | | `serviceApiUri` | string | The complete URL for accessing the API. | -## 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/ptn/azd/apim-api/main.bicep b/avm/ptn/azd/apim-api/main.bicep index 22c2fd5435..becb6b512e 100644 --- a/avm/ptn/azd/apim-api/main.bicep +++ b/avm/ptn/azd/apim-api/main.bicep @@ -24,7 +24,7 @@ param apiDescription string @minLength(1) param apiPath string -@description('Required. Absolute URL of the web frontend.') +@description('Required. Absolute URL of web frontend.') param webFrontendUrl string @description('Optional. Location for all Resources.') diff --git a/avm/ptn/azd/apim-api/main.json b/avm/ptn/azd/apim-api/main.json index dacd440b8a..912dbe4412 100644 --- a/avm/ptn/azd/apim-api/main.json +++ b/avm/ptn/azd/apim-api/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "7935494033060946539" + "templateHash": "1542387667896789833" }, "name": "avm/ptn/azd/apim-api", "description": "Creates and configure an API within an API Management service instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -50,7 +50,7 @@ "webFrontendUrl": { "type": "string", "metadata": { - "description": "Required. Absolute URL of the web frontend." + "description": "Required. Absolute URL of web frontend." } }, "location": { diff --git a/avm/ptn/azd/container-apps/README.md b/avm/ptn/azd/container-apps-stack/README.md similarity index 89% rename from avm/ptn/azd/container-apps/README.md rename to avm/ptn/azd/container-apps-stack/README.md index 413bf894be..a01a8ffb71 100644 --- a/avm/ptn/azd/container-apps/README.md +++ b/avm/ptn/azd/container-apps-stack/README.md @@ -1,7 +1,9 @@ -# avm/ptn/azd/container-apps `[Azd/ContainerApps]` +# avm/ptn/azd/container-apps-stack `[Azd/ContainerAppsStack]` Creates an Azure Container Registry and an Azure Container Apps environment. +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case + ## Navigation - [Resource Types](#Resource-Types) @@ -35,7 +37,7 @@ The following section provides usage examples for the module, which were used to >**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/ptn/azd/container-apps:`. +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/container-apps-stack:`. - [With zoneRedundant enabled](#example-1-with-zoneredundant-enabled) @@ -49,12 +51,12 @@ This instance deploys the module with zoneRedundant enabled.

via Bicep module ```bicep -module containerApps 'br/public:avm/ptn/azd/container-apps:' = { - name: 'containerAppsDeployment' +module containerAppsStack 'br/public:avm/ptn/azd/container-apps-stack:' = { + name: 'containerAppsStackDeployment' params: { // Required parameters - containerAppsEnvironmentName: 'acazrcae001' - containerRegistryName: 'acazrcr001' + containerAppsEnvironmentName: 'acaszrcae001' + containerRegistryName: 'acaszrcr001' logAnalyticsWorkspaceResourceId: '' // Non-required parameters acrSku: 'Standard' @@ -83,7 +85,7 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = {
-via JSON Parameter file +via JSON parameters file ```json { @@ -92,10 +94,10 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = { "parameters": { // Required parameters "containerAppsEnvironmentName": { - "value": "acazrcae001" + "value": "acaszrcae001" }, "containerRegistryName": { - "value": "acazrcr001" + "value": "acaszrcr001" }, "logAnalyticsWorkspaceResourceId": { "value": "" @@ -145,6 +147,40 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/container-apps-stack:' + +// Required parameters +param containerAppsEnvironmentName = 'acaszrcae001' +param containerRegistryName = 'acaszrcr001' +param logAnalyticsWorkspaceResourceId = '' +// Non-required parameters +param acrSku = 'Standard' +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetResourceId = '' +param internal = true +param location = '' +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +param zoneRedundant = true +``` + +
+

+ ## Parameters **Required parameters** @@ -161,7 +197,7 @@ module containerApps 'br/public:avm/ptn/azd/container-apps:' = { | :-- | :-- | :-- | | [`dockerBridgeCidr`](#parameter-dockerbridgecidr) | string | CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`infrastructureSubnetResourceId`](#parameter-infrastructuresubnetresourceid) | string | Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if "internal" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant. | -| [`internal`](#parameter-internal) | bool | Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant. | +| [`internal`](#parameter-internal) | bool | Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant. | | [`platformReservedCidr`](#parameter-platformreservedcidr) | string | IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`platformReservedDnsIP`](#parameter-platformreserveddnsip) | string | An IP address from the IP range defined by "platformReservedCidr" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`workloadProfiles`](#parameter-workloadprofiles) | array | Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant. | @@ -220,7 +256,7 @@ Resource ID of a subnet for infrastructure components. This is used to deploy th ### Parameter: `internal` -Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant. +Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant. - Required: No - Type: bool diff --git a/avm/ptn/azd/container-apps/main.bicep b/avm/ptn/azd/container-apps-stack/main.bicep similarity index 88% rename from avm/ptn/azd/container-apps/main.bicep rename to avm/ptn/azd/container-apps-stack/main.bicep index 9a99522cd4..db11a5ed46 100644 --- a/avm/ptn/azd/container-apps/main.bicep +++ b/avm/ptn/azd/container-apps-stack/main.bicep @@ -1,5 +1,7 @@ -metadata name = 'avm/ptn/azd/container-apps' -metadata description = 'Creates an Azure Container Registry and an Azure Container Apps environment.' +metadata name = 'avm/ptn/azd/container-apps-stack' +metadata description = '''Creates an Azure Container Registry and an Azure Container Apps environment. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case''' metadata owner = 'Azure/module-maintainers' @description('Optional. Location for all Resources.') @@ -51,7 +53,7 @@ param dockerBridgeCidr string = '' @description('Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if "internal" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant.') param infrastructureSubnetResourceId string = '' -@description('Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant.') +@description('Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if \'zoneRedundant\' is set to true to make the resource WAF compliant.') param internal bool = false @description('Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant.') @@ -68,7 +70,7 @@ param infrastructureResourceGroupName string = take('ME_${containerAppsEnvironme #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { - name: '46d3xbcp.ptn.azd-containerapps.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + name: '46d3xbcp.ptn.azd-containerappsstack.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' properties: { mode: 'Incremental' template: { @@ -102,6 +104,7 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.7.0 dockerBridgeCidr: dockerBridgeCidr platformReservedCidr: platformReservedCidr platformReservedDnsIP: platformReservedDnsIP + enableTelemetry: enableTelemetry } } @@ -116,6 +119,7 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = acrAdminUserEnabled: acrAdminUserEnabled tags: tags acrSku: acrSku + enableTelemetry: enableTelemetry } } diff --git a/avm/ptn/azd/container-apps/main.json b/avm/ptn/azd/container-apps-stack/main.json similarity index 99% rename from avm/ptn/azd/container-apps/main.json rename to avm/ptn/azd/container-apps-stack/main.json index b781ce346e..49ae1b6b15 100644 --- a/avm/ptn/azd/container-apps/main.json +++ b/avm/ptn/azd/container-apps-stack/main.json @@ -5,11 +5,11 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "3154922260961626340" + "version": "0.30.23.60470", + "templateHash": "2135275469617068705" }, - "name": "avm/ptn/azd/container-apps", - "description": "Creates an Azure Container Registry and an Azure Container Apps environment.", + "name": "avm/ptn/azd/container-apps-stack", + "description": "Creates an Azure Container Registry and an Azure Container Apps environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", "owner": "Azure/module-maintainers" }, "parameters": { @@ -117,7 +117,7 @@ "type": "bool", "defaultValue": false, "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant." } }, "platformReservedCidr": { @@ -154,7 +154,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.ptn.azd-containerapps.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.ptn.azd-containerappsstack.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { diff --git a/avm/ptn/azd/container-apps/tests/e2e/zone-redundant/dependencies.bicep b/avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/dependencies.bicep similarity index 100% rename from avm/ptn/azd/container-apps/tests/e2e/zone-redundant/dependencies.bicep rename to avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/dependencies.bicep diff --git a/avm/ptn/azd/container-apps/tests/e2e/zone-redundant/main.test.bicep b/avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/main.test.bicep similarity index 97% rename from avm/ptn/azd/container-apps/tests/e2e/zone-redundant/main.test.bicep rename to avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/main.test.bicep index 19ec8ef14a..06ec762ffc 100644 --- a/avm/ptn/azd/container-apps/tests/e2e/zone-redundant/main.test.bicep +++ b/avm/ptn/azd/container-apps-stack/tests/e2e/zone-redundant/main.test.bicep @@ -8,13 +8,13 @@ metadata description = 'This instance deploys the module with zoneRedundant enab // ========== // @description('Optional. The name of the resource group to deploy for testing purposes.') @maxLength(90) -param resourceGroupName string = 'dep-${namePrefix}-container-apps-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-container-apps-stack-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -param serviceShort string = 'acazr' +param serviceShort string = 'acaszr' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' diff --git a/avm/ptn/azd/container-apps/version.json b/avm/ptn/azd/container-apps-stack/version.json similarity index 100% rename from avm/ptn/azd/container-apps/version.json rename to avm/ptn/azd/container-apps-stack/version.json diff --git a/avm/ptn/azd/insights-dashboard/README.md b/avm/ptn/azd/insights-dashboard/README.md index 92e51c5d57..db6912ad8b 100644 --- a/avm/ptn/azd/insights-dashboard/README.md +++ b/avm/ptn/azd/insights-dashboard/README.md @@ -62,7 +62,7 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,23 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/insights-dashboard:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'aidmin001' +// Non-required parameters +param location = '' +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module using large parameters. @@ -117,7 +134,7 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

-via JSON Parameter file +via JSON parameters file ```json { @@ -151,6 +168,26 @@ module insightsDashboard 'br/public:avm/ptn/azd/insights-dashboard:' =

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/insights-dashboard:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'icmax001' +// Non-required parameters +param applicationType = 'web' +param dashboardName = 'icmaxdb001' +param kind = 'web' +param location = '' +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/azd/insights-dashboard/main.bicep b/avm/ptn/azd/insights-dashboard/main.bicep index 911a2471a7..929b1fd5be 100644 --- a/avm/ptn/azd/insights-dashboard/main.bicep +++ b/avm/ptn/azd/insights-dashboard/main.bicep @@ -72,6 +72,7 @@ module applicationInsights 'br/public:avm/res/insights/component:0.4.1' = { kind: kind applicationType: applicationType workspaceResourceId: logAnalyticsWorkspaceResourceId + enableTelemetry: enableTelemetry } } @@ -82,6 +83,7 @@ module applicationInsightsDashboard 'modules/applicationinsights-dashboard.bicep location: location applicationInsightsName: applicationInsights.outputs.name applicationInsightsResourceId: applicationInsights.outputs.resourceId + enableTelemetry: enableTelemetry } } @@ -102,7 +104,9 @@ output dashboardName string = !empty(dashboardName) ? applicationInsightsDashboa output applicationInsightsResourceId string = applicationInsights.outputs.resourceId @description('The resource ID of the dashboard.') -output dashboardResourceId string = !empty(dashboardName) ? applicationInsightsDashboard.outputs.dashboardResourceId : '' +output dashboardResourceId string = !empty(dashboardName) + ? applicationInsightsDashboard.outputs.dashboardResourceId + : '' @description('The connection string of the application insights.') output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString diff --git a/avm/ptn/azd/insights-dashboard/main.json b/avm/ptn/azd/insights-dashboard/main.json index ed2893f7d0..a082c79e6f 100644 --- a/avm/ptn/azd/insights-dashboard/main.json +++ b/avm/ptn/azd/insights-dashboard/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16185324363882257699" + "version": "0.30.23.60470", + "templateHash": "15067669928476640283" }, "name": "Application Insights Components", "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -121,6 +121,9 @@ }, "workspaceResourceId": { "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -758,6 +761,9 @@ }, "applicationInsightsResourceId": { "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -767,8 +773,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "12382758204242351890" + "version": "0.30.23.60470", + "templateHash": "10844955132300564569" }, "name": "Azure Portal Dashboard", "description": "Creates a dashboard for an Application Insights instance.", @@ -800,6 +806,13 @@ "description": "Optional. Location for all Resources." } }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "tags": { "type": "object", "nullable": true, @@ -829,6 +842,9 @@ "tags": { "value": "[parameters('tags')]" }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, "lenses": { "value": [ { diff --git a/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep b/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep index 4a08622f49..f358fa0a74 100644 --- a/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep +++ b/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep @@ -14,6 +14,9 @@ param applicationInsightsResourceId string @description('Optional. Location for all Resources.') param location string = resourceGroup().location +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + @description('Optional. Tags of the resource.') @metadata({ example: ''' @@ -35,6 +38,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:0.1.0' = { name: name location: location tags: tags + enableTelemetry: enableTelemetry lenses: [ { order: 0 diff --git a/avm/ptn/azd/ml-hub-dependencies/README.md b/avm/ptn/azd/ml-hub-dependencies/README.md new file mode 100644 index 0000000000..7a9f689c43 --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/README.md @@ -0,0 +1,901 @@ +# Azd Azure Machine Learning Dependencies `[Azd/MlHubDependencies]` + +Creates all the dependencies required for a Machine Learning Service. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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.CognitiveServices/accounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts) | +| `Microsoft.CognitiveServices/accounts/deployments` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts/deployments) | +| `Microsoft.ContainerRegistry/registries` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries) | +| `Microsoft.ContainerRegistry/registries/cacheRules` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/cacheRules) | +| `Microsoft.ContainerRegistry/registries/credentialSets` | [2023-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/credentialSets) | +| `Microsoft.ContainerRegistry/registries/replications` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/replications) | +| `Microsoft.ContainerRegistry/registries/scopeMaps` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/scopeMaps) | +| `Microsoft.ContainerRegistry/registries/webhooks` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/webhooks) | +| `Microsoft.Insights/components` | [2020-02-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2020-02-02/components) | +| `microsoft.insights/components/linkedStorageAccounts` | [2020-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/microsoft.insights/2020-03-01-preview/components/linkedStorageAccounts) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/accessPolicies) | +| `Microsoft.KeyVault/vaults/keys` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/keys) | +| `Microsoft.KeyVault/vaults/secrets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/secrets) | +| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.OperationalInsights/workspaces` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces) | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataExports) | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataSources) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedServices) | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedStorageAccounts) | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/savedSearches) | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/storageInsightConfigs) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces/tables) | +| `Microsoft.OperationsManagement/solutions` | [2015-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationsManagement/2015-11-01-preview/solutions) | +| `Microsoft.Portal/dashboards` | [2020-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Portal/2020-09-01-preview/dashboards) | +| `Microsoft.Search/searchServices` | [2024-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2024-03-01-preview/searchServices) | +| `Microsoft.Search/searchServices/sharedPrivateLinkResources` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2023-11-01/searchServices/sharedPrivateLinkResources) | +| `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | +| `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | +| `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | +| `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | + +## 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/ptn/azd/ml-hub-dependencies:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module mlHubDependencies 'br/public:avm/ptn/azd/ml-hub-dependencies:' = { + name: 'mlHubDependenciesDeployment' + params: { + // Required parameters + cognitiveServicesName: 'cog07hubdmin' + keyVaultName: 'key07hubdmin' + storageAccountName: 'st07hubdmin' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "cognitiveServicesName": { + "value": "cog07hubdmin" + }, + "keyVaultName": { + "value": "key07hubdmin" + }, + "storageAccountName": { + "value": "st07hubdmin" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-hub-dependencies:' + +// Required parameters +param cognitiveServicesName = 'cog07hubdmin' +param keyVaultName = 'key07hubdmin' +param storageAccountName = 'st07hubdmin' +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module using large parameters. + + +

+ +via Bicep module + +```bicep +module mlHubDependencies 'br/public:avm/ptn/azd/ml-hub-dependencies:' = { + name: 'mlHubDependenciesDeployment' + params: { + // Required parameters + cognitiveServicesName: 'cs08mhdpmax' + keyVaultName: 'kv08mhdpmax' + storageAccountName: 'sa08mhdpmax' + // Non-required parameters + applicationInsightsDashboardName: 'aid08mhdpmax' + applicationInsightsName: 'ai08mhdpmax' + containerRegistryName: 'cr08mhdpmax' + logAnalyticsName: 'log08mhdpmax' + searchServiceName: 'sea08mhdpmax' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "cognitiveServicesName": { + "value": "cs08mhdpmax" + }, + "keyVaultName": { + "value": "kv08mhdpmax" + }, + "storageAccountName": { + "value": "sa08mhdpmax" + }, + // Non-required parameters + "applicationInsightsDashboardName": { + "value": "aid08mhdpmax" + }, + "applicationInsightsName": { + "value": "ai08mhdpmax" + }, + "containerRegistryName": { + "value": "cr08mhdpmax" + }, + "logAnalyticsName": { + "value": "log08mhdpmax" + }, + "searchServiceName": { + "value": "sea08mhdpmax" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-hub-dependencies:' + +// Required parameters +param cognitiveServicesName = 'cs08mhdpmax' +param keyVaultName = 'kv08mhdpmax' +param storageAccountName = 'sa08mhdpmax' +// Non-required parameters +param applicationInsightsDashboardName = 'aid08mhdpmax' +param applicationInsightsName = 'ai08mhdpmax' +param containerRegistryName = 'cr08mhdpmax' +param logAnalyticsName = 'log08mhdpmax' +param searchServiceName = 'sea08mhdpmax' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`cognitiveServicesName`](#parameter-cognitiveservicesname) | string | Name of the OpenAI cognitive services. | +| [`keyVaultName`](#parameter-keyvaultname) | string | Name of the key vault. | +| [`storageAccountName`](#parameter-storageaccountname) | string | Name of the storage account. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowBlobPublicAccess`](#parameter-allowblobpublicaccess) | bool | Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false. | +| [`applicationInsightsDashboardName`](#parameter-applicationinsightsdashboardname) | string | The resource portal dashboards name. | +| [`applicationInsightsName`](#parameter-applicationinsightsname) | string | The resource insights components name. | +| [`authOptions`](#parameter-authoptions) | object | Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true. | +| [`blobServices`](#parameter-blobservices) | object | Blob service and containers to deploy. | +| [`cmkEnforcement`](#parameter-cmkenforcement) | string | Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys. | +| [`cognitiveServicesCustomSubDomainName`](#parameter-cognitiveservicescustomsubdomainname) | string | The custom subdomain name used to access the API. Defaults to the value of the name parameter. | +| [`cognitiveServicesDeployments`](#parameter-cognitiveservicesdeployments) | array | Array of deployments about cognitive service accounts to create. | +| [`cognitiveServicesDisableLocalAuth`](#parameter-cognitiveservicesdisablelocalauth) | bool | Allow only Azure AD authentication. Should be enabled for security reasons. | +| [`cognitiveServicesKind`](#parameter-cognitiveserviceskind) | string | Kind of the Cognitive Services. | +| [`cognitiveServicesNetworkAcls`](#parameter-cognitiveservicesnetworkacls) | object | A collection of rules governing the accessibility from specific network locations. | +| [`cognitiveServicesPublicNetworkAccess`](#parameter-cognitiveservicespublicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | +| [`cognitiveServicesSku`](#parameter-cognitiveservicessku) | string | SKU of the Cognitive Services resource. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | Name of the container registry. | +| [`dataRetention`](#parameter-dataretention) | int | Number of days data will be retained for. | +| [`disableLocalAuth`](#parameter-disablelocalauth) | bool | When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined. | +| [`dnsEndpointType`](#parameter-dnsendpointtype) | string | Allows you to specify the type of endpoint in the storage account. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier. | +| [`enablePurgeProtection`](#parameter-enablepurgeprotection) | bool | Provide 'true' to enable Key Vault's purge protection feature. | +| [`enableRbacAuthorization`](#parameter-enablerbacauthorization) | bool | Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`enableVaultForDeployment`](#parameter-enablevaultfordeployment) | bool | Specifies if the vault is enabled for deployment by script or compute. | +| [`enableVaultForTemplateDeployment`](#parameter-enablevaultfortemplatedeployment) | bool | Specifies if the vault is enabled for a template deployment. | +| [`fileServices`](#parameter-fileservices) | object | File service and shares to deploy. | +| [`hostingMode`](#parameter-hostingmode) | string | Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'. | +| [`keyVaultSku`](#parameter-keyvaultsku) | string | Specifies the SKU for the vault. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The resource operational insights workspaces name. | +| [`logAnalyticsSkuName`](#parameter-loganalyticsskuname) | string | The name of the SKU. | +| [`networkAcls`](#parameter-networkacls) | object | Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny. | +| [`networkRuleSet`](#parameter-networkruleset) | object | Network specific rules that determine how the Azure Cognitive Search service may be reached. | +| [`partitionCount`](#parameter-partitioncount) | int | The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for the storage account. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | +| [`queueServices`](#parameter-queueservices) | object | Queue service and queues to create. | +| [`registryAcrSku`](#parameter-registryacrsku) | string | Tier of your Azure container registry. | +| [`registryPublicNetworkAccess`](#parameter-registrypublicnetworkaccess) | string | Public network access setting. | +| [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | +| [`searchServiceName`](#parameter-searchservicename) | string | Name of the Azure Cognitive Search service. | +| [`searchServicePublicNetworkAccess`](#parameter-searchservicepublicnetworkaccess) | string | This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. | +| [`searchServiceSku`](#parameter-searchservicesku) | string | Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. | +| [`semanticSearch`](#parameter-semanticsearch) | string | Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. | +| [`tableServices`](#parameter-tableservices) | object | Table service and tables to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `cognitiveServicesName` + +Name of the OpenAI cognitive services. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +Name of the key vault. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountName` + +Name of the storage account. + +- Required: Yes +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `allowBlobPublicAccess` + +Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `applicationInsightsDashboardName` + +The resource portal dashboards name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `applicationInsightsName` + +The resource insights components name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `authOptions` + +Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `blobServices` + +Blob service and containers to deploy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + containerDeleteRetentionPolicyDays: 7 + containers: [ + { + name: 'default' + } + ] + corsRules: [ + { + allowedHeaders: [ + '*' + ] + allowedMethods: [ + 'DELETE' + 'GET' + 'HEAD' + 'OPTIONS' + 'PATCH' + 'POST' + 'PUT' + ] + allowedOrigins: [ + 'https://*.ai.azure.com' + 'https://*.ml.azure.com' + 'https://ai.azure.com' + 'https://ml.azure.com' + 'https://mlworkspace.azure.ai' + 'https://mlworkspace.azureml-test.net' + 'https://mlworkspacecanary.azure.ai' + ] + exposedHeaders: [ + '*' + ] + maxAgeInSeconds: 1800 + } + ] + deleteRetentionPolicyAllowPermanentDelete: true + deleteRetentionPolicyDays: 6 + deleteRetentionPolicyEnabled: true + } + ``` + +### Parameter: `cmkEnforcement` + +Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys. + +- Required: No +- Type: string +- Default: `'Unspecified'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + 'Unspecified' + ] + ``` + +### Parameter: `cognitiveServicesCustomSubDomainName` + +The custom subdomain name used to access the API. Defaults to the value of the name parameter. + +- Required: No +- Type: string +- Default: `[parameters('cognitiveServicesName')]` + +### Parameter: `cognitiveServicesDeployments` + +Array of deployments about cognitive service accounts to create. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `cognitiveServicesDisableLocalAuth` + +Allow only Azure AD authentication. Should be enabled for security reasons. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `cognitiveServicesKind` + +Kind of the Cognitive Services. + +- Required: No +- Type: string +- Default: `'AIServices'` + +### Parameter: `cognitiveServicesNetworkAcls` + +A collection of rules governing the accessibility from specific network locations. + +- Required: No +- Type: object +- Default: + ```Bicep + { + defaultAction: 'Allow' + } + ``` + +### Parameter: `cognitiveServicesPublicNetworkAccess` + +Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. + +- Required: No +- Type: string +- Default: `'Disabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `cognitiveServicesSku` + +SKU of the Cognitive Services resource. + +- Required: No +- Type: string +- Default: `'S0'` + +### Parameter: `containerRegistryName` + +Name of the container registry. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `dataRetention` + +Number of days data will be retained for. + +- Required: No +- Type: int +- Default: `30` + +### Parameter: `disableLocalAuth` + +When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `dnsEndpointType` + +Allows you to specify the type of endpoint in the storage account. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + '' + 'AzureDnsZone' + 'Standard' + ] + ``` + +### Parameter: `enablePurgeProtection` + +Provide 'true' to enable Key Vault's purge protection feature. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableRbacAuthorization` + +Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableVaultForDeployment` + +Specifies if the vault is enabled for deployment by script or compute. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableVaultForTemplateDeployment` + +Specifies if the vault is enabled for a template deployment. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `fileServices` + +File service and shares to deploy. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: 'default' + } + ``` + +### Parameter: `hostingMode` + +Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'. + +- Required: No +- Type: string +- Default: `'default'` +- Allowed: + ```Bicep + [ + 'default' + 'highDensity' + ] + ``` + +### Parameter: `keyVaultSku` + +Specifies the SKU for the vault. + +- Required: No +- Type: string +- Default: `'standard'` +- Allowed: + ```Bicep + [ + 'premium' + 'standard' + ] + ``` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `logAnalyticsName` + +The resource operational insights workspaces name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `logAnalyticsSkuName` + +The name of the SKU. + +- Required: No +- Type: string +- Default: `'PerGB2018'` +- Allowed: + ```Bicep + [ + 'CapacityReservation' + 'Free' + 'LACluster' + 'PerGB2018' + 'PerNode' + 'Premium' + 'Standalone' + 'Standard' + ] + ``` + +### Parameter: `networkAcls` + +Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny. + +- Required: No +- Type: object +- Default: + ```Bicep + { + bypass: 'AzureServices' + defaultAction: 'Allow' + } + ``` + +### Parameter: `networkRuleSet` + +Network specific rules that determine how the Azure Cognitive Search service may be reached. + +- Required: No +- Type: object +- Default: + ```Bicep + { + bypass: 'None' + ipRules: [] + } + ``` + +### Parameter: `partitionCount` + +The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for the storage account. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + '' + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `queueServices` + +Queue service and queues to create. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: 'default' + } + ``` + +### Parameter: `registryAcrSku` + +Tier of your Azure container registry. + +- Required: No +- Type: string +- Default: `'Basic'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `registryPublicNetworkAccess` + +Public network access setting. + +- Required: No +- Type: string +- Default: `'Enabled'` + +### Parameter: `replicaCount` + +The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. + +- Required: No +- Type: int +- Default: `1` + +### Parameter: `searchServiceName` + +Name of the Azure Cognitive Search service. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `searchServicePublicNetworkAccess` + +This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `searchServiceSku` + +Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. + +- Required: No +- Type: string +- Default: `'standard'` +- Allowed: + ```Bicep + [ + 'basic' + 'free' + 'standard' + 'standard2' + 'standard3' + 'storage_optimized_l1' + 'storage_optimized_l2' + ] + ``` + +### Parameter: `semanticSearch` + +Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. + +- Required: No +- Type: string +- Default: `'disabled'` +- Allowed: + ```Bicep + [ + 'disabled' + 'free' + 'standard' + ] + ``` + +### Parameter: `tableServices` + +Table service and tables to create. + +- Required: No +- Type: object +- Default: + ```Bicep + { + name: 'default' + } + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationInsightsConnectionString` | string | The connection string of the application insights. | +| `applicationInsightsInstrumentationKey` | string | The instrumentation key of the application insights. | +| `applicationInsightsName` | string | The name of the application insights. | +| `applicationInsightsResourceId` | string | The resource ID of the application insights. | +| `cognitiveServicesEndpoint` | string | The endpoint of the cognitive services. | +| `cognitiveServicesName` | string | The name of the cognitive services. | +| `cognitiveServicesResourceId` | string | The resource ID of the cognitive services. | +| `containerRegistryEndpoint` | string | The endpoint of the container registry. | +| `containerRegistryName` | string | The name of the container registry. | +| `containerRegistryResourceId` | string | The resource ID of the container registry. | +| `keyVaultEndpoint` | string | The endpoint of the key vault. | +| `keyVaultName` | string | The name of the key vault. | +| `keyVaultResourceId` | string | The resource ID of the key vault. | +| `logAnalyticsWorkspaceName` | string | The name of the loganalytics workspace. | +| `logAnalyticsWorkspaceResourceId` | string | The resource ID of the loganalytics workspace. | +| `resourceGroupName` | string | The name of the resource group the module was deployed to. | +| `searchServiceEndpoint` | string | The endpoint of the search service. | +| `searchServiceName` | string | The name of the search service. | +| `searchServiceResourceId` | string | The resource ID of the search service. | +| `storageAccountName` | string | The name of the storage account. | +| `storageAccountResourceId` | string | The resource ID of the storage account. | +| `systemAssignedMiPrincipalId` | string | The system assigned mi principal Id key of the search service. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/ptn/azd/insights-dashboard:0.1.0` | Remote reference | +| `br/public:avm/res/cognitive-services/account:0.7.0` | Remote reference | +| `br/public:avm/res/container-registry/registry:0.4.0` | Remote reference | +| `br/public:avm/res/key-vault/vault:0.7.1` | Remote reference | +| `br/public:avm/res/operational-insights/workspace:0.6.0` | Remote reference | +| `br/public:avm/res/search/search-service:0.6.0` | Remote reference | +| `br/public:avm/res/storage/storage-account:0.9.1` | Remote reference | + +## 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/ptn/azd/ml-hub-dependencies/main.bicep b/avm/ptn/azd/ml-hub-dependencies/main.bicep index 0d2d3e3c37..d35212616c 100644 --- a/avm/ptn/azd/ml-hub-dependencies/main.bicep +++ b/avm/ptn/azd/ml-hub-dependencies/main.bicep @@ -1,4 +1,4 @@ -metadata name = 'Azure Machine Learning Dependencies' +metadata name = 'Azd Azure Machine Learning Dependencies' metadata description = '''Creates all the dependencies required for a Machine Learning Service. **Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' @@ -303,6 +303,7 @@ module keyVault 'br/public:avm/res/key-vault/vault:0.7.1' = { enableVaultForTemplateDeployment: enableVaultForTemplateDeployment enablePurgeProtection: enablePurgeProtection sku: keyVaultSku + enableTelemetry: enableTelemetry } } @@ -320,6 +321,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { fileServices: fileServices queueServices: queueServices tableServices: tableServices + enableTelemetry: enableTelemetry } } @@ -336,6 +338,7 @@ module cognitiveServices 'br/public:avm/res/cognitive-services/account:0.7.0' = disableLocalAuth: cognitiveServicesDisableLocalAuth sku: cognitiveServicesSku deployments: cognitiveServicesDeployments + enableTelemetry: enableTelemetry } } @@ -347,6 +350,7 @@ module logAnalytics 'br/public:avm/res/operational-insights/workspace:0.6.0' = i tags: tags dataRetention: dataRetention skuName: logAnalyticsSkuName + enableTelemetry: enableTelemetry } } @@ -358,6 +362,7 @@ module applicationInsights 'br/public:avm/ptn/azd/insights-dashboard:0.1.0' = if name: applicationInsightsName dashboardName: applicationInsightsDashboardName logAnalyticsWorkspaceResourceId: !empty(logAnalyticsName) ? logAnalytics.outputs.resourceId : '' + enableTelemetry: enableTelemetry } } @@ -369,6 +374,7 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = tags: tags location: location publicNetworkAccess: registryPublicNetworkAccess + enableTelemetry: enableTelemetry } } @@ -389,6 +395,7 @@ module searchService 'br/public:avm/res/search/search-service:0.6.0' = if (!empt semanticSearch: semanticSearch sku: searchServiceSku managedIdentities: managedIdentities + enableTelemetry: enableTelemetry } } diff --git a/avm/ptn/azd/ml-hub-dependencies/main.json b/avm/ptn/azd/ml-hub-dependencies/main.json new file mode 100644 index 0000000000..4a195bc5a7 --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/main.json @@ -0,0 +1,18738 @@ +{ + "$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.30.23.60470", + "templateHash": "7687704138266254216" + }, + "name": "Azd Azure Machine Learning Dependencies", + "description": "Creates all the dependencies required for a Machine Learning Service.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + } + }, + "parameters": { + "applicationInsightsDashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource insights components name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "logAnalyticsName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource operational insights workspaces name." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. Name of the key vault." + } + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "Required. Name of the storage account." + } + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "Required. Name of the OpenAI cognitive services." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the container registry." + } + }, + "searchServiceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Azure Cognitive Search service." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint in the storage account. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for the storage account. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "networkAcls": { + "type": "object", + "defaultValue": { + "bypass": "AzureServices", + "defaultAction": "Allow" + }, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "blobServices": { + "type": "object", + "defaultValue": { + "containers": [ + { + "name": "default" + } + ], + "corsRules": [ + { + "allowedOrigins": [ + "https://mlworkspace.azure.ai", + "https://ml.azure.com", + "https://*.ml.azure.com", + "https://ai.azure.com", + "https://*.ai.azure.com", + "https://mlworkspacecanary.azure.ai", + "https://mlworkspace.azureml-test.net" + ], + "allowedMethods": [ + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "PATCH" + ], + "maxAgeInSeconds": 1800, + "exposedHeaders": [ + "*" + ], + "allowedHeaders": [ + "*" + ] + } + ], + "deleteRetentionPolicyEnabled": true, + "containerDeleteRetentionPolicyDays": 7, + "deleteRetentionPolicyDays": 6, + "deleteRetentionPolicyAllowPermanentDelete": true + }, + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": { + "name": "default" + }, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "cognitiveServicesKind": { + "type": "string", + "defaultValue": "AIServices", + "metadata": { + "description": "Optional. Kind of the Cognitive Services." + } + }, + "cognitiveServicesDeployments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + }, + "cognitiveServicesCustomSubDomainName": { + "type": "string", + "defaultValue": "[parameters('cognitiveServicesName')]", + "metadata": { + "description": "Optional. The custom subdomain name used to access the API. Defaults to the value of the name parameter." + } + }, + "cognitiveServicesDisableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "cognitiveServicesPublicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "cognitiveServicesNetworkAcls": { + "type": "object", + "defaultValue": { + "defaultAction": "Allow" + }, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "cognitiveServicesSku": { + "type": "string", + "defaultValue": "S0", + "metadata": { + "description": "Optional. SKU of the Cognitive Services resource." + } + }, + "registryAcrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "registryPublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "metadata": { + "description": "Optional. Public network access setting." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "keyVaultSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "logAnalyticsSkuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 30, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "authOptions": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default", + "highDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "networkRuleSet": { + "type": "object", + "defaultValue": { + "bypass": "None", + "ipRules": [] + }, + "metadata": { + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "searchServicePublicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "semanticSearch": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "searchServiceSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "nullable": true, + "metadata": { + "description": "Conditional. The managed identity definition for this resource. Required if `assignRbacRole` is `true` and `managedIdentityName` is `null`." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlhubdependencies.{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" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableRbacAuthorization": { + "value": "[parameters('enableRbacAuthorization')]" + }, + "enableVaultForDeployment": { + "value": "[parameters('enableVaultForDeployment')]" + }, + "enableVaultForTemplateDeployment": { + "value": "[parameters('enableVaultForTemplateDeployment')]" + }, + "enablePurgeProtection": { + "value": "[parameters('enablePurgeProtection')]" + }, + "sku": { + "value": "[parameters('keyVaultSku')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "6878673228466609441" + }, + "name": "Key Vaults", + "description": "This module deploys a Key Vault.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "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, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "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 + }, + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + }, + "secretsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the secret is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the secret." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "keysType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the key is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the key." + } + }, + "curveName": { + "type": "string", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "nullable": true, + "metadata": { + "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." + } + }, + "keyOps": { + "type": "array", + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "release", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. The allowed operations on this key." + } + }, + "keySize": { + "type": "int", + "allowedValues": [ + 2048, + 3072, + 4096 + ], + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." + } + }, + "kty": { + "type": "string", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the key. Default is \"EC\"." + } + }, + "releasePolicy": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Content type and version of key release policy." + } + }, + "data": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Blob encoding the policy rules under which the key can be released." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "rotationPolicy": { + "$ref": "#/definitions/rotationPoliciesType", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "rotationPoliciesType": { + "type": "object", + "properties": { + "attributes": { + "type": "object", + "properties": { + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The attributes of key rotation policy." + } + }, + "lifetimeActions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Notify", + "Rotate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of action." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The action of key rotation policy lifetimeAction." + } + }, + "trigger": { + "type": "object", + "properties": { + "timeAfterCreate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + }, + "timeBeforeExpiry": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The trigger of key rotation policy lifetimeAction." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The lifetimeActions for key rotation action." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Key Vault. Must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. All access policies to create." + } + }, + "secrets": { + "$ref": "#/definitions/secretsType", + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "$ref": "#/definitions/keysType", + "nullable": true, + "metadata": { + "description": "Optional. All keys to create." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "sku": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Rules governing the accessibility of the resource from specific network locations." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "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." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "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": "2024-03-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.7.1', '.', '-'), 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" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[variables('formattedAccessPolicies')]", + "sku": { + "name": "[parameters('sku')]", + "family": "A" + }, + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" + } + }, + "keyVault_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.KeyVault/vaults/{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": [ + "keyVault" + ] + }, + "keyVault_diagnosticSettings": { + "copy": { + "name": "keyVault_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_roleAssignments": { + "copy": { + "name": "keyVault_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_accessPolicies": { + "condition": "[not(empty(parameters('accessPolicies')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('name')]" + }, + "accessPolicies": { + "value": "[parameters('accessPolicies')]" + } + }, + "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.29.47.4906", + "templateHash": "7494731697751039419" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(coalesce(parameters('secrets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.29.47.4906", + "templateHash": "4990258423482296566" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "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": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_keys": { + "copy": { + "name": "keyVault_keys", + "count": "[length(coalesce(parameters('keys'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", + "releasePolicy": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" + }, + "kty": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "rotationPolicy": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + } + }, + "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.29.47.4906", + "templateHash": "10436564794447478489" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "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": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "curveName": "[parameters('curveName')]", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "kty": "[parameters('kty')]", + "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", + "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote 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')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', 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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The URI of the key vault." + }, + "value": "[reference('keyVault').vaultUri]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('keyVault', '2022-07-01', 'full').location]" + } + } + } + } + }, + "storageAccount": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-storage', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('storageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowBlobPublicAccess": { + "value": "[parameters('allowBlobPublicAccess')]" + }, + "dnsEndpointType": { + "value": "[parameters('dnsEndpointType')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "networkAcls": { + "value": "[parameters('networkAcls')]" + }, + "blobServices": { + "value": "[parameters('blobServices')]" + }, + "fileServices": { + "value": "[parameters('fileServices')]" + }, + "queueServices": { + "value": "[parameters('queueServices')]" + }, + "tableServices": { + "value": "[parameters('tableServices')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.28.1.47646", + "templateHash": "3958760216991467865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "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 + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The Storage Account ManagementPolicies Rules." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "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." + } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + } + }, + "variables": { + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "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(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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.9.1', '.', '-'), 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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_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.Storage/storageAccounts/{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": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts', 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": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote 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')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', 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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(parameters('managementPolicyRules'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[coalesce(parameters('managementPolicyRules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "9473195527943694039" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "description": "Required. The Storage Account ManagementPolicies Rules." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + }, + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(parameters('localUsers'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('localUsers')[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[parameters('localUsers')[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[parameters('localUsers')[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[parameters('localUsers')[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'sshAuthorizedKeys')]" + } + }, + "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.28.1.47646", + "templateHash": "14968464858285923305" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "sshAuthorizedKeysType": { + "type": "secureObject", + "properties": { + "secureList": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "string", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + } + }, + "metadata": { + "description": "Optional. The list of SSH authorized keys." + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "$ref": "#/definitions/sshAuthorizedKeysType", + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[tryGet(parameters('sshAuthorizedKeys'), 'secureList')]" + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "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.28.1.47646", + "templateHash": "2306287879023715578" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies CORS rules for the Blob service. You can include up to five CorsRule elements in the request. If no CorsRule elements are included in the request body, all CORS rules will be deleted, and CORS will be disabled for the Blob service." + } + }, + "defaultServiceVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 6, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": { + "corsRules": "[parameters('corsRules')]" + }, + "defaultServiceVersion": "[if(not(empty(parameters('defaultServiceVersion'))), parameters('defaultServiceVersion'), null())]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(not(equals(reference('storageAccount', '2022-09-01', 'full').kind, 'Storage')), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicyProperties": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicyProperties')]" + } + }, + "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.28.1.47646", + "templateHash": "7045309160947869799" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicyName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. Name of the immutable policy." + } + }, + "immutabilityPolicyProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair to associate with the container as metadata." + } + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(equals(parameters('immutableStorageWithVersioningEnabled'), true()), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + }, + "dependsOn": [ + "storageAccount::blobServices" + ] + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', 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": [ + "container" + ] + }, + "immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicyProperties'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('immutabilityPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWritesAll')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "2543276032744560941" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "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.28.1.47646", + "templateHash": "7463227074634701879" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "1342480740201032357" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + }, + "dependsOn": [ + "storageAccount::fileService" + ] + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "8779226603522513073" + } + }, + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "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", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "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" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[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": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + } + }, + "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.28.1.47646", + "templateHash": "10678250016540336570" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "13487964166280180730" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Required. A name-value pair that represents queue metadata." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + }, + "dependsOn": [ + "storageAccount::queueServices" + ] + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', 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": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + } + }, + "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.28.1.47646", + "templateHash": "16839054392438941735" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "3177845984945141330" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "dependsOn": [ + "storageAccount::tableServices" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', 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": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + } + }, + "cognitiveServices": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitive', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('cognitiveServicesName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('cognitiveServicesKind')]" + }, + "customSubDomainName": { + "value": "[parameters('cognitiveServicesCustomSubDomainName')]" + }, + "publicNetworkAccess": { + "value": "[parameters('cognitiveServicesPublicNetworkAccess')]" + }, + "networkAcls": { + "value": "[parameters('cognitiveServicesNetworkAcls')]" + }, + "disableLocalAuth": { + "value": "[parameters('cognitiveServicesDisableLocalAuth')]" + }, + "sku": { + "value": "[parameters('cognitiveServicesSku')]" + }, + "deployments": { + "value": "[parameters('cognitiveServicesDeployments')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "7976342392137470716" + }, + "name": "Cognitive Services", + "description": "This module deploys a Cognitive Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "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, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "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 + }, + "deploymentsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of cognitive service account deployment." + } + }, + "model": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account deployment model." + } + }, + "format": { + "type": "string", + "metadata": { + "description": "Required. The format of Cognitive Services account deployment model." + } + }, + "version": { + "type": "string", + "metadata": { + "description": "Required. The version of Cognitive Services account deployment model." + } + } + }, + "metadata": { + "description": "Required. Properties of Cognitive Services account deployment model." + } + }, + "sku": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource model definition representing SKU." + } + }, + "capacity": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The capacity of the resource model definition representing SKU." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource model definition representing SKU." + } + }, + "raiPolicyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of RAI policy." + } + } + } + }, + "nullable": true + }, + "endpointsType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Type of the endpoint." + } + }, + "endpoint": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The endpoint URI." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of Cognitive Services account." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AIServices", + "AnomalyDetector", + "CognitiveServices", + "ComputerVision", + "ContentModerator", + "ContentSafety", + "ConversationalLanguageUnderstanding", + "CustomVision.Prediction", + "CustomVision.Training", + "Face", + "FormRecognizer", + "HealthInsights", + "ImmersiveReader", + "Internal.AllInOne", + "LUIS", + "LUIS.Authoring", + "LanguageAuthoring", + "MetricsAdvisor", + "OpenAI", + "Personalizer", + "QnAMaker.v2", + "SpeechServices", + "TextAnalytics", + "TextTranslation" + ], + "metadata": { + "description": "Required. Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "sku": { + "type": "string", + "defaultValue": "S0", + "allowedValues": [ + "C2", + "C3", + "C4", + "F0", + "F1", + "S", + "S0", + "S1", + "S10", + "S2", + "S3", + "S4", + "S5", + "S6", + "S7", + "S8", + "S9" + ], + "metadata": { + "description": "Optional. SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "customSubDomainName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. A collection of rules governing the accessibility from specific network locations." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "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." + } + }, + "allowedFqdnList": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of allowed FQDN." + } + }, + "apiProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The API properties for special APIs." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "dynamicThrottlingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to enable dynamic throttling." + } + }, + "migrationToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource migration token." + } + }, + "restore": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." + } + }, + "restrictOutboundNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Restrict outbound network access." + } + }, + "userOwnedStorage": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The storage accounts for this resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "deployments": { + "$ref": "#/definitions/deploymentsType", + "metadata": { + "description": "Optional. Array of deployments about cognitive service accounts to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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(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": { + "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", + "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", + "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", + "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", + "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", + "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", + "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", + "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", + "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", + "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", + "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", + "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", + "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", + "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", + "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", + "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", + "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", + "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", + "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", + "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", + "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", + "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", + "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", + "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('0.7.0', '.', '-'), 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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "cognitiveService": { + "type": "Microsoft.CognitiveServices/accounts", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "kind": "[parameters('kind')]", + "identity": "[variables('identity')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "properties": { + "customSubDomainName": "[parameters('customSubDomainName')]", + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", + "allowedFqdnList": "[parameters('allowedFqdnList')]", + "apiProperties": "[parameters('apiProperties')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", + "migrationToken": "[parameters('migrationToken')]", + "restore": "[parameters('restore')]", + "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", + "userOwnedStorage": "[parameters('userOwnedStorage')]", + "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "cognitiveService_deployments": { + "copy": { + "name": "cognitiveService_deployments", + "count": "[length(coalesce(parameters('deployments'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.CognitiveServices/accounts/deployments", + "apiVersion": "2023-05-01", + "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", + "properties": { + "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", + "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]" + }, + "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku')))]", + "dependsOn": [ + "cognitiveService" + ] + }, + "cognitiveService_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.CognitiveServices/accounts/{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": [ + "cognitiveService" + ] + }, + "cognitiveService_diagnosticSettings": { + "copy": { + "name": "cognitiveService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "cognitiveService" + ] + }, + "cognitiveService_roleAssignments": { + "copy": { + "name": "cognitiveService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "cognitiveService" + ] + }, + "cognitiveService_privateEndpoints": { + "copy": { + "name": "cognitiveService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.29.47.4906", + "templateHash": "13720311665093076615" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.6.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "15263454436186512874" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "cognitiveService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services account." + }, + "value": "[resourceId('Microsoft.CognitiveServices/accounts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the cognitive services account was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The service endpoint of the cognitive services account." + }, + "value": "[reference('cognitiveService').endpoint]" + }, + "endpoints": { + "$ref": "#/definitions/endpointsType", + "metadata": { + "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." + }, + "value": "[reference('cognitiveService').endpoints]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('cognitiveService', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('cognitiveService', '2023-05-01', 'full').location]" + } + } + } + } + }, + "logAnalytics": { + "condition": "[not(empty(parameters('logAnalyticsName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-loganalytics', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('logAnalyticsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": "[parameters('dataRetention')]" + }, + "skuName": { + "value": "[parameters('logAnalyticsSkuName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "14441228139596902410" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "metadata": { + "description": "Optional. The workspace daily quota for ingestion." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "useResourcePermissions": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "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": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "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')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.6.0', '.', '-'), 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" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[parameters('useResourcePermissions')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[parameters('dailyQuotaGb')]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]" + }, + "identity": "[variables('identity')]" + }, + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_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.OperationalInsights/workspaces/{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": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(parameters('storageInsightsConfigs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageInsightsConfigs')[copyIndex()].storageAccountResourceId]" + } + }, + "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.29.47.4906", + "templateHash": "1745671120474305926" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2022-09-01').keys[0].value]" + } + }, + "dependsOn": [ + "storageAccount", + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(parameters('linkedServices'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('linkedServices')[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'writeAccessResourceId')]" + } + }, + "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.29.47.4906", + "templateHash": "12032441371027552374" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Required. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[if(empty(parameters('writeAccessResourceId')), null(), parameters('writeAccessResourceId'))]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(parameters('linkedStorageAccounts'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('linkedStorageAccounts')[copyIndex()].name]" + }, + "resourceId": { + "value": "[parameters('linkedStorageAccounts')[copyIndex()].resourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "12623216644328477682" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": [ + "[parameters('resourceId')]" + ] + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(parameters('savedSearches'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', parameters('savedSearches')[copyIndex()].name, uniqueString(deployment().name))]" + }, + "etag": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[parameters('savedSearches')[copyIndex()].displayName]" + }, + "category": { + "value": "[parameters('savedSearches')[copyIndex()].category]" + }, + "query": { + "value": "[parameters('savedSearches')[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionParameters')]" + }, + "version": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'version')]" + } + }, + "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.29.47.4906", + "templateHash": "7683333179440464721" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(parameters('dataExports'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('dataExports')[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5765609820817623497" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(parameters('dataSources'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('dataSources')[copyIndex()].name]" + }, + "kind": { + "value": "[parameters('dataSources')[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'performanceCounters')]" + } + }, + "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.29.47.4906", + "templateHash": "13460038983765020046" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Required. The kind of the DataSource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "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.29.47.4906", + "templateHash": "6905244456918791391" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention." + } + }, + "schema": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "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": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[parameters('retentionInDays')]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[parameters('totalRetentionInDays')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(parameters('gallerySolutions'))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('gallerySolutions')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "product": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'product')]" + }, + "publisher": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'publisher')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('gallerySolutions')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18444780972506374592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution. For Microsoft published gallery solution the target solution resource name will be composed as `{name}({logAnalyticsWorkspaceName})`." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "product": { + "type": "string", + "defaultValue": "OMSGallery", + "metadata": { + "description": "Optional. The product of the deployed solution. For Microsoft published gallery solution it should be `OMSGallery` and the target solution resource product will be composed as `OMSGallery/{name}`. For third party solution, it can be anything. This is case sensitive." + } + }, + "publisher": { + "type": "string", + "defaultValue": "Microsoft", + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "solutionName": "[if(equals(parameters('publisher'), 'Microsoft'), format('{0}({1})', parameters('name'), parameters('logAnalyticsWorkspaceName')), parameters('name'))]", + "solutionProduct": "[if(equals(parameters('publisher'), 'Microsoft'), format('OMSGallery/{0}', parameters('name')), parameters('product'))]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.1.0', '.', '-'), 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" + } + } + } + } + }, + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[variables('solutionName')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[variables('solutionName')]", + "promotionCode": "", + "product": "[variables('solutionProduct')]", + "publisher": "[parameters('publisher')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[variables('solutionName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName')), '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2022-10-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('logAnalyticsWorkspace', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + } + }, + "applicationInsights": { + "condition": "[and(not(empty(parameters('applicationInsightsName'))), not(empty(parameters('logAnalyticsName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-insights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "name": { + "value": "[parameters('applicationInsightsName')]" + }, + "dashboardName": { + "value": "[parameters('applicationInsightsDashboardName')]" + }, + "logAnalyticsWorkspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), createObject('value', reference('logAnalytics').outputs.resourceId.value), createObject('value', ''))]", + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "17156187352453961206" + }, + "name": "Application Insights Components", + "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "dashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the loganalytics workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-insightsdashboard.{0}.{1}', replace('0.1.0', '.', '-'), 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" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appinsights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "applicationType": { + "value": "[parameters('applicationType')]" + }, + "workspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "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.29.47.4906", + "templateHash": "10653241142071426932" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.4.1', '.', '-'), 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" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[parameters('linkedStorageAccountResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "216781367921725873" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } + } + } + }, + "applicationInsightsDashboard": { + "condition": "[not(empty(parameters('dashboardName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "application-insights-dashboard", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('dashboardName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "applicationInsightsName": { + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "applicationInsightsResourceId": { + "value": "[reference('applicationInsights').outputs.resourceId.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.29.47.4906", + "templateHash": "9856731218551847403" + }, + "name": "Azure Portal Dashboard", + "description": "Creates a dashboard for an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The portal dashboard name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components ID." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "dashboard": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "dashboard-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "lenses": { + "value": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 2, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "id", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart", + "asset": { + "idInputName": "id", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "overview" + } + }, + { + "position": { + "x": 2, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "ProactiveDetection" + } + }, + { + "position": { + "x": 3, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + } + ], + "type": "Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:20:33.345Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 5, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-08T18:47:35.237Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "ConfigurationId", + "value": "78ce933e-e864-4b05-a27b-71fd55a6afad" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AppMapButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 0, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Usage", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 3, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:22:35.782Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + } + ], + "type": "Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Reliability", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 7, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:42:40.072Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "failures" + } + }, + { + "position": { + "x": 8, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Responsiveness\r\n", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 11, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:43:37.804Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "2a8ede4f-2bee-4b9c-aed9-2db0e8a01865", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "performance" + } + }, + { + "position": { + "x": 12, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Browser", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 15, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "MetricsExplorerJsonDefinitionId", + "value": "BrowserPerformanceTimelineMetrics" + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "createdTime": "2018-05-08T12:16:27.534Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "CurrentFilter", + "value": { + "eventTypes": [ + 4, + 1, + 3, + 5, + 2, + 6, + 13 + ], + "typeFacets": {}, + "isPermissive": false + } + }, + { + "name": "id", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "browser" + } + }, + { + "position": { + "x": 0, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "sessions/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Sessions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "users/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Users", + "color": "#7E58FF" + } + } + ], + "title": "Unique sessions and users", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "segmentationUsers" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Failed requests", + "color": "#EC008C" + } + } + ], + "title": "Failed requests", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "failures" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/duration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server response time", + "color": "#00BCF2" + } + } + ], + "title": "Server response time", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "performance" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/networkDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Page load network connect time", + "color": "#7E58FF" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/processingDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Client processing time", + "color": "#44F1C8" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/sendDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Send request time", + "color": "#EB9371" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/receiveDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Receiving response time", + "color": "#0672F1" + } + } + ], + "title": "Average page load time breakdown", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/availabilityPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability", + "color": "#47BDF5" + } + } + ], + "title": "Average availability", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "availability" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/server", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server exceptions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "dependencies/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Dependency failures", + "color": "#7E58FF" + } + } + ], + "title": "Server exceptions and Dependency failures", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processorCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Processor time", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process CPU", + "color": "#7E58FF" + } + } + ], + "title": "Average processor and process CPU utilization", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/browser", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Browser exceptions", + "color": "#47BDF5" + } + } + ], + "title": "Browser exceptions", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/count", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability test results count", + "color": "#47BDF5" + } + } + ], + "title": "Availability test results count", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processIOBytesPerSecond", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process IO rate", + "color": "#47BDF5" + } + } + ], + "title": "Average process I/O rate", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/memoryAvailableBytes", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Available memory", + "color": "#47BDF5" + } + } + ], + "title": "Average available memory", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + } + ] + } + ] + } + }, + "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.28.1.47646", + "templateHash": "12676032921679464791" + }, + "name": "Portal Dashboards", + "description": "This module deploys a Portal Dashboard.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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 + }, + "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 + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the dashboard to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "lenses": { + "type": "array", + "items": { + "type": "object" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The dashboard lenses." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The dashboard metadata." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.portal-dashboard.{0}.{1}', replace('0.1.0', '.', '-'), 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" + } + } + } + } + }, + "dashboard": { + "type": "Microsoft.Portal/dashboards", + "apiVersion": "2020-09-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "lenses": "[parameters('lenses')]", + "metadata": "[parameters('metadata')]" + } + }, + "dashboard_roleAssignments": { + "copy": { + "name": "dashboard_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Portal/dashboards/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Portal/dashboards', 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": [ + "dashboard" + ] + }, + "dashboard_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.Portal/dashboards/{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": [ + "dashboard" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[resourceId('Microsoft.Portal/dashboards', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dashboard was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the dashboard." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the dashboard was deployed into." + }, + "value": "[reference('dashboard', '2020-09-01-preview', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[reference('dashboard').outputs.resourceId.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[reference('dashboard').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "applicationInsights" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardName.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardResourceId.value, '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.connectionString.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[reference('applicationInsights').outputs.instrumentationKey.value]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + }, + "containerRegistry": { + "condition": "[not(empty(parameters('containerRegistryName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('containerRegistryName')]" + }, + "acrSku": { + "value": "[parameters('registryAcrSku')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "publicNetworkAccess": { + "value": "[parameters('registryPublicNetworkAccess')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "8799580877381308457" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "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, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registr is enabled or not. Default is enabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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(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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(not(empty(parameters('networkRuleSetIpRules'))), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', parameters('networkRuleSetIpRules')), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "registry_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.ContainerRegistry/registries/{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": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + } + }, + "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.29.47.4906", + "templateHash": "9144531012597082524" + }, + "name": "Container Registries scopeMaps", + "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "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.29.47.4906", + "templateHash": "8531695368487734118" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + } + }, + "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.29.47.4906", + "templateHash": "12196074162662855376" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + } + }, + "authCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "authCredentials": { + "$ref": "#/definitions/authCredentialsType", + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "variables": { + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]" + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2023-11-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[variables('identity')]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('credentialSet', '2023-11-01-preview', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name'), replace(replace(coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository, '/', '-'), '.', '-'))]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "4294329625336671928" + }, + "name": "Container Registries Cache", + "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be dereived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action'), createArray('chart_delete', 'chart_push', 'delete', 'push', 'quarantine'))]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "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.29.47.4906", + "templateHash": "14912363209364245195" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote 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')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', 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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2019-05-01').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('registry', '2023-06-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2023-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.systemAssignedMIPrincipalId.value]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.resourceId.value]" + } + } + } + } + } + }, + "searchService": { + "condition": "[not(empty(parameters('searchServiceName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchservice', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('searchServiceName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "authOptions": { + "value": "[parameters('authOptions')]" + }, + "disableLocalAuth": { + "value": "[parameters('disableLocalAuth')]" + }, + "cmkEnforcement": { + "value": "[parameters('cmkEnforcement')]" + }, + "hostingMode": { + "value": "[parameters('hostingMode')]" + }, + "networkRuleSet": { + "value": "[parameters('networkRuleSet')]" + }, + "partitionCount": { + "value": "[parameters('partitionCount')]" + }, + "publicNetworkAccess": { + "value": "[parameters('searchServicePublicNetworkAccess')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "semanticSearch": { + "value": "[parameters('semanticSearch')]" + }, + "sku": { + "value": "[parameters('searchServiceSku')]" + }, + "managedIdentities": { + "value": "[parameters('managedIdentities')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "14924554723661229870" + }, + "name": "Search Services", + "description": "This module deploys a Search Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "nullable": true + }, + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "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, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Azure Cognitive Search service to create or update. Search service names must only contain lowercase letters, digits or dashes, cannot use dash as the first two or last one characters, cannot contain consecutive dashes, and must be between 2 and 60 characters in length. Search service names must be globally unique since they are part of the service URI (https://.search.windows.net). You cannot change the service name after the service is created." + } + }, + "authOptions": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Defines the options for how the data plane API of a Search service authenticates requests. Must remain an empty object {} if 'disableLocalAuth' is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. When set to true, calls to the search service will not be permitted to utilize API keys for authentication. This cannot be set to true if 'authOptions' are defined." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "cmkEnforcement": { + "type": "string", + "defaultValue": "Unspecified", + "allowedValues": [ + "Disabled", + "Enabled", + "Unspecified" + ], + "metadata": { + "description": "Optional. Describes a policy that determines how resources within the search service are to be encrypted with Customer Managed Keys." + } + }, + "hostingMode": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default", + "highDensity" + ], + "metadata": { + "description": "Optional. Applicable only for the standard3 SKU. You can set this property to enable up to 3 high density partitions that allow up to 1000 indexes, which is much higher than the maximum indexes allowed for any other SKU. For the standard3 SKU, the value is either 'default' or 'highDensity'. For all other SKUs, this value must be 'default'." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "networkRuleSet": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Network specific rules that determine how the Azure Cognitive Search service may be reached." + } + }, + "partitionCount": { + "type": "int", + "defaultValue": 1, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of partitions in the search service; if specified, it can be 1, 2, 3, 4, 6, or 12. Values greater than 1 are only valid for standard SKUs. For 'standard3' services with hostingMode set to 'highDensity', the allowed values are between 1 and 3." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The sharedPrivateLinkResources to create as part of the search Service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." + } + }, + "replicaCount": { + "type": "int", + "defaultValue": 3, + "minValue": 1, + "maxValue": 12, + "metadata": { + "description": "Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "semanticSearch": { + "type": "string", + "nullable": true, + "allowedValues": [ + "disabled", + "free", + "standard" + ], + "metadata": { + "description": "Optional. Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations." + } + }, + "sku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "free", + "standard", + "standard2", + "standard3", + "storage_optimized_l1", + "storage_optimized_l2" + ], + "metadata": { + "description": "Optional. Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to help categorize the resource in the Azure portal." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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(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', '')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Search Index Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')]", + "Search Index Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1407120a-92aa-4202-b7e9-c0e197c71c8f')]", + "Search Service Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.search-searchservice.{0}.{1}', replace('0.6.0', '.', '-'), 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" + } + } + } + } + }, + "searchService": { + "type": "Microsoft.Search/searchServices", + "apiVersion": "2024-03-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('sku')]" + }, + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "authOptions": "[if(not(empty(parameters('authOptions'))), parameters('authOptions'), null())]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryptionWithCmk": { + "enforcement": "[parameters('cmkEnforcement')]" + }, + "hostingMode": "[parameters('hostingMode')]", + "networkRuleSet": "[parameters('networkRuleSet')]", + "partitionCount": "[parameters('partitionCount')]", + "replicaCount": "[parameters('replicaCount')]", + "publicNetworkAccess": "[toLower(parameters('publicNetworkAccess'))]", + "semanticSearch": "[parameters('semanticSearch')]" + } + }, + "searchService_diagnosticSettings": { + "copy": { + "name": "searchService_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_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.Search/searchServices/{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": [ + "searchService" + ] + }, + "searchService_roleAssignments": { + "copy": { + "name": "searchService_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Search/searchServices/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Search/searchServices', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_privateEndpoints": { + "copy": { + "name": "searchService_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Search/searchServices', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'searchService')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "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.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + }, + "searchService_sharedPrivateLinkResources": { + "copy": { + "name": "searchService_sharedPrivateLinkResources", + "count": "[length(parameters('sharedPrivateLinkResources'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-searchService-SharedPrivateLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'name'), format('spl-{0}-{1}-{2}', last(split(resourceId('Microsoft.Search/searchServices', parameters('name')), '/')), parameters('sharedPrivateLinkResources')[copyIndex()].groupId, copyIndex()))]" + }, + "searchServiceName": { + "value": "[parameters('name')]" + }, + "privateLinkResourceId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].privateLinkResourceId]" + }, + "groupId": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].groupId]" + }, + "requestMessage": { + "value": "[parameters('sharedPrivateLinkResources')[copyIndex()].requestMessage]" + }, + "resourceRegion": { + "value": "[tryGet(parameters('sharedPrivateLinkResources')[copyIndex()], 'resourceRegion')]" + } + }, + "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.29.47.4906", + "templateHash": "2330033720810948871" + }, + "name": "Search Services Private Link Resources", + "description": "This module deploys a Search Service Private Link Resource.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "searchServiceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent searchServices. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the shared private link resource managed by the Azure Cognitive Search service within the specified resource group." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource the shared private link resource is for." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The group ID from the provider of resource the shared private link resource is for." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Required. The request message for requesting approval of the shared private link resource." + } + }, + "resourceRegion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Can be used to specify the Azure Resource Manager location of the resource to which a shared private link is to be created. This is only required for those resources whose DNS configuration are regional (such as Azure Kubernetes Service)." + } + } + }, + "resources": { + "searchService": { + "existing": true, + "type": "Microsoft.Search/searchServices", + "apiVersion": "2023-11-01", + "name": "[parameters('searchServiceName')]" + }, + "sharedPrivateLinkResource": { + "type": "Microsoft.Search/searchServices/sharedPrivateLinkResources", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('searchServiceName'), parameters('name'))]", + "properties": { + "privateLinkResourceId": "[parameters('privateLinkResourceId')]", + "groupId": "[parameters('groupId')]", + "requestMessage": "[parameters('requestMessage')]", + "resourceRegion": "[parameters('resourceRegion')]" + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the shared private link resource." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the shared private link resource." + }, + "value": "[resourceId('Microsoft.Search/searchServices/sharedPrivateLinkResources', parameters('searchServiceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the shared private link resource was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "searchService" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[resourceId('Microsoft.Search/searchServices', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the search service was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('searchService', '2024-03-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('searchService', '2024-03-01-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the search service." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the module was deployed to." + }, + "value": "[resourceGroup().name]" + }, + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[reference('keyVault').outputs.resourceId.value]" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[reference('keyVault').outputs.name.value]" + }, + "keyVaultEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the key vault." + }, + "value": "[reference('keyVault').outputs.uri.value]" + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the storage account." + }, + "value": "[reference('storageAccount').outputs.resourceId.value]" + }, + "storageAccountName": { + "type": "string", + "metadata": { + "description": "The name of the storage account." + }, + "value": "[reference('storageAccount').outputs.name.value]" + }, + "containerRegistryResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.resourceId.value, '')]" + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The name of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.name.value, '')]" + }, + "containerRegistryEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the container registry." + }, + "value": "[if(not(empty(parameters('containerRegistryName'))), reference('containerRegistry').outputs.loginServer.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsResourceId.value, '')]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsName.value, '')]" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the loganalytics workspace." + }, + "value": "[if(not(empty(parameters('logAnalyticsName'))), reference('logAnalytics').outputs.resourceId.value, '')]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the loganalytics workspace." + }, + "value": "[if(not(empty(parameters('logAnalyticsName'))), reference('logAnalytics').outputs.name.value, '')]" + }, + "cognitiveServicesResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.resourceId.value]" + }, + "cognitiveServicesName": { + "type": "string", + "metadata": { + "description": "The name of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.name.value]" + }, + "cognitiveServicesEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the cognitive services." + }, + "value": "[reference('cognitiveServices').outputs.endpoint.value]" + }, + "searchServiceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.resourceId.value, '')]" + }, + "searchServiceName": { + "type": "string", + "metadata": { + "description": "The name of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.name.value, '')]" + }, + "searchServiceEndpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), format('https://{0}.search.windows.net/', reference('searchService').outputs.name.value), '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsConnectionString.value, '')]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[if(not(empty(parameters('applicationInsightsName'))), reference('applicationInsights').outputs.applicationInsightsInstrumentationKey.value, '')]" + }, + "systemAssignedMiPrincipalId": { + "type": "string", + "metadata": { + "description": "The system assigned mi principal Id key of the search service." + }, + "value": "[if(not(empty(parameters('searchServiceName'))), reference('searchService').outputs.systemAssignedMIPrincipalId.value, '')]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/ml-hub-dependencies/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..478ac9d83c --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-ml-hub-dependencies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'hubdmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + cognitiveServicesName: '${namePrefix}cog07${serviceShort}' + keyVaultName: '${namePrefix}key07${serviceShort}' + storageAccountName: '${namePrefix}st07${serviceShort}' + } + } +] diff --git a/avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..19b3dd9ecd --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/tests/e2e/max/main.test.bicep @@ -0,0 +1,54 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module using large parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-ml-hub-dependencies-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'mhdpmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + cognitiveServicesName: '${namePrefix}cs08${serviceShort}' + keyVaultName: '${namePrefix}kv08${serviceShort}' + storageAccountName: '${namePrefix}sa08${serviceShort}' + applicationInsightsDashboardName: '${namePrefix}aid08${serviceShort}' + applicationInsightsName: '${namePrefix}ai08${serviceShort}' + logAnalyticsName: '${namePrefix}log08${serviceShort}' + containerRegistryName: '${namePrefix}cr08${serviceShort}' + searchServiceName: '${namePrefix}sea08${serviceShort}' + } + } +] diff --git a/avm/ptn/azd/ml-hub-dependencies/version.json b/avm/ptn/azd/ml-hub-dependencies/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/ml-hub-dependencies/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/ptn/deployment-script/import-image-to-acr/README.md b/avm/ptn/deployment-script/import-image-to-acr/README.md index b079fe65c1..0e878635e3 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/README.md +++ b/avm/ptn/deployment-script/import-image-to-acr/README.md @@ -62,7 +62,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

-via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,25 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/deployment-script/import-image-to-acr:' + +// Required parameters +param acrName = '' +param image = 'mcr.microsoft.com/k8se/quickstart-jobs:latest' +param name = 'dsiitamin001' +// Non-required parameters +param location = '' +param overwriteExistingImage = true +``` + +
+

+ ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -115,7 +134,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr cleanupPreference: 'OnExpiration' location: '' managedIdentities: '' - newImageName: 'your-image-name:tag' + newImageName: 'application/your-image-name:tag' overwriteExistingImage: true storageAccountResourceId: '' subnetResourceIds: '' @@ -132,7 +151,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

-via JSON Parameter file +via JSON parameters file ```json { @@ -163,7 +182,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr "value": "" }, "newImageName": { - "value": "your-image-name:tag" + "value": "application/your-image-name:tag" }, "overwriteExistingImage": { "value": true @@ -187,6 +206,35 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/deployment-script/import-image-to-acr:' + +// Required parameters +param acrName = '' +param image = 'mcr.microsoft.com/k8se/quickstart-jobs:latest' +param name = 'dsiitamax001' +// Non-required parameters +param assignRbacRole = true +param cleanupPreference = 'OnExpiration' +param location = '' +param managedIdentities = '' +param newImageName = 'application/your-image-name:tag' +param overwriteExistingImage = true +param storageAccountResourceId = '' +param subnetResourceIds = '' +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
+

+ ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -217,7 +265,7 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

-via JSON Parameter file +via JSON parameters file ```json { @@ -251,6 +299,26 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/deployment-script/import-image-to-acr:' + +// Required parameters +param acrName = '' +param image = 'mcr.microsoft.com/k8se/quickstart-jobs:latest' +param name = 'dsiitawaf001' +// Non-required parameters +param location = '' +param managedIdentities = '' +param overwriteExistingImage = true +``` + +
+

+ ## Parameters **Required parameters** @@ -281,6 +349,8 @@ module importImageToAcr 'br/public:avm/ptn/deployment-script/import-image-to-acr | [`overwriteExistingImage`](#parameter-overwriteexistingimage) | bool | The image will be overwritten if it already exists in the ACR with the same tag. Default is false. | | [`retryMax`](#parameter-retrymax) | int | The maximum number of retries for the script import operation. Default is 3. | | [`runOnce`](#parameter-runonce) | bool | How the deployment script should be forced to execute. Default is to force the script to deploy the image to run every time. | +| [`sourceRegistryPassword`](#parameter-sourceregistrypassword) | securestring | The password for the source registry. Required if the source registry is private, or to logon to the public docker registry. | +| [`sourceRegistryUsername`](#parameter-sourceregistryusername) | string | The username for the source registry. Required if the source registry is private, or to logon to the public docker registry. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | The resource id of the storage account to use for the deployment script. An existing storage account is needed, if PrivateLink is going to be used for the deployment script. | | [`subnetResourceIds`](#parameter-subnetresourceids) | array | The subnet ids to use for the deployment script. An existing subnet is needed, if PrivateLink is going to be used for the deployment script. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -298,7 +368,12 @@ A fully qualified image name to import. - Required: Yes - Type: string -- Example: `mcr.microsoft.com/k8se/quickstart-jobs:latest` +- Example: + ```Bicep + mcr.microsoft.com/k8se/quickstart-jobs:latest + docker.io/library/image:latest + docker.io/hello-world:latest + ``` ### Parameter: `name` @@ -388,7 +463,7 @@ The new image name in the ACR. You can use this to import a publically available - Required: No - Type: string -- Default: `[last(split(parameters('image'), '/'))]` +- Default: `[string(skip(parameters('image'), add(indexOf(parameters('image'), '/'), 1)))]` - Example: `your-image-name:tag` ### Parameter: `overwriteExistingImage` @@ -415,6 +490,22 @@ How the deployment script should be forced to execute. Default is to force the s - Type: bool - Default: `False` +### Parameter: `sourceRegistryPassword` + +The password for the source registry. Required if the source registry is private, or to logon to the public docker registry. + +- Required: No +- Type: securestring +- Default: `''` + +### Parameter: `sourceRegistryUsername` + +The username for the source registry. Required if the source registry is private, or to logon to the public docker registry. + +- Required: No +- Type: string +- Default: `''` + ### Parameter: `storageAccountResourceId` The resource id of the storage account to use for the deployment script. An existing storage account is needed, if PrivateLink is going to be used for the deployment script. @@ -458,13 +549,17 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/resources/deployment-script:0.2.3` | Remote reference | +| `br/public:avm/res/resources/deployment-script:0.4.0` | Remote reference | ## Notes The deployment script service will need and provision a Storage Account as well as a Container Instance to execute the provided script. _The deployment script resource is available only in the regions where Azure Container Instances is available._ -> The service cleans up these resources after the deployment script finishes. You incur charges for these resources until they're removed. +> The service cleans up these resources after the deployment script finishes. You incur charges for these resources until they are removed. + +### Authentication to source Container Registry + +Authentication is possible by setting the ```sourceRegistryUsername``` and ```sourceRegistryPassword``` parameters. An example that uses Key Vault is in the max sample. It is commented out, as for the shared environments no user exists, that could be used to access e.g. docker hub images. ### Private network access diff --git a/avm/ptn/deployment-script/import-image-to-acr/main.bicep b/avm/ptn/deployment-script/import-image-to-acr/main.bicep index eb578a27a1..e6c532e567 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/main.bicep +++ b/avm/ptn/deployment-script/import-image-to-acr/main.bicep @@ -28,15 +28,26 @@ param managedIdentityName string? @description('Required. A fully qualified image name to import.') @metadata({ - example: 'mcr.microsoft.com/k8se/quickstart-jobs:latest' + example: [ + 'mcr.microsoft.com/k8se/quickstart-jobs:latest' + 'docker.io/library/image:latest' + 'docker.io/hello-world:latest' + ] }) param image string +@description('Optional. The username for the source registry. Required if the source registry is private, or to logon to the public docker registry.') +param sourceRegistryUsername string = '' + +@description('Optional. The password for the source registry. Required if the source registry is private, or to logon to the public docker registry.') +@secure() +param sourceRegistryPassword string = '' + @description('Optional. The new image name in the ACR. You can use this to import a publically available image with a custom name for later updating from e.g., your build pipeline.') @metadata({ example: 'your-image-name:tag' }) -param newImageName string = last(split(image, '/')) +param newImageName string = string(skip(image, indexOf(image, '/') + 1)) @description('Optional. The image will be overwritten if it already exists in the ACR with the same tag. Default is false.') param overwriteExistingImage bool = false @@ -147,7 +158,7 @@ resource acrRoleAssignmentNewManagedIdentity 'Microsoft.Authorization/roleAssign } } -module imageImport 'br/public:avm/res/resources/deployment-script:0.2.3' = { +module imageImport 'br/public:avm/res/resources/deployment-script:0.4.0' = { name: name ?? 'ACR-Import-${last(split(replace(image,':','-'),'/'))}' scope: resourceGroup() params: { @@ -159,48 +170,25 @@ module imageImport 'br/public:avm/res/resources/deployment-script:0.2.3' = { : { userAssignedResourcesIds: [newManagedIdentity.id] } kind: 'AzureCLI' runOnce: runOnce - azCliVersion: '2.61.0' // available tags are listed here: https://mcr.microsoft.com/v2/azure-cli/tags/list + azCliVersion: '2.63.0' // available tags are listed here: https://mcr.microsoft.com/v2/azure-cli/tags/list timeout: 'PT30M' // set timeout to 30m retentionInterval: 'PT1H' // cleanup after 1h - environmentVariables: { - secureList: [ - { - name: 'acrName' - value: acrName - } - { - name: 'imageName' - value: image - } - { - name: 'newImageName' - value: newImageName - } - { - name: 'overwriteExistingImage' - value: toLower(string(overwriteExistingImage)) - } - { - name: 'initialDelay' - value: '${string(initialScriptDelay)}s' - } - { - name: 'retryMax' - value: string(retryMax) - } - { - name: 'retrySleep' - value: '5s' - } - ] - } + environmentVariables: [ + { name: 'acrName', value: acrName } + { name: 'imageName', value: image } + { name: 'newImageName', value: newImageName } + { name: 'overwriteExistingImage', value: toLower(string(overwriteExistingImage)) } + { name: 'initialDelay', value: '${string(initialScriptDelay)}s' } + { name: 'retryMax', value: string(retryMax) } + { name: 'retrySleep', value: '5s' } + { name: 'sourceRegistryUsername', value: sourceRegistryUsername } + { name: 'sourceRegistryPassword', secureValue: sourceRegistryPassword } + ] cleanupPreference: cleanupPreference storageAccountResourceId: storageAccountResourceId containerGroupName: '${resourceGroup().name}-infrastructure' subnetResourceIds: subnetResourceIds scriptContent: '''#!/bin/bash - set -e - echo "Waiting on RBAC replication ($initialDelay)\n" sleep $initialDelay @@ -210,9 +198,17 @@ module imageImport 'br/public:avm/res/resources/deployment-script:0.2.3' = { do echo "Importing Image ($retryLoopCount): $imageName into ACR: $acrName\n" if [ $overwriteExistingImage = 'true' ]; then - az acr import -n $acrName --source $imageName --image $newImageName --force + if [ -n "$sourceRegistryUsername" ] && [ -n "$sourceRegistryPassword" ]; then + az acr import -n $acrName --source $imageName --image $newImageName --force --username $sourceRegistryUsername --password $sourceRegistryPassword + else + az acr import -n $acrName --source $imageName --image $newImageName --force + fi else - az acr import -n $acrName --source $imageName --image $newImageName + if [ -n "$sourceRegistryUsername" ] && [ -n "$sourceRegistryPassword" ]; then + az acr import -n $acrName --source $imageName --image $newImageName --username $sourceRegistryUsername --password $sourceRegistryPassword + else + az acr import -n $acrName --source $imageName --image $newImageName + fi fi sleep $retrySleep @@ -236,7 +232,9 @@ output deploymentScriptOutput string[] = imageImport.outputs.deploymentScriptLog @description('An array of the imported images.') output importedImage importedImageType = { originalImage: image - acrHostedImage: '${acr.properties.loginServer}${string(skip(image, indexOf(image,'/')))}' + acrHostedImage: empty(newImageName) + ? '${acr.properties.loginServer}${string(skip(image, indexOf(image,'/')))}' + : '${acr.properties.loginServer}/${newImageName}' } // ================ // diff --git a/avm/ptn/deployment-script/import-image-to-acr/main.json b/avm/ptn/deployment-script/import-image-to-acr/main.json index ffc946ccc3..6bfe24d5cd 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/main.json +++ b/avm/ptn/deployment-script/import-image-to-acr/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "18410876545978102921" + "version": "0.30.3.12046", + "templateHash": "17375159703541878382" }, "name": "import-image-to-acr", "description": "This modules deployes an image to an Azure Container Registry.", @@ -103,13 +103,31 @@ "image": { "type": "string", "metadata": { - "example": "mcr.microsoft.com/k8se/quickstart-jobs:latest", + "example": [ + "mcr.microsoft.com/k8se/quickstart-jobs:latest", + "docker.io/library/image:latest", + "docker.io/hello-world:latest" + ], "description": "Required. A fully qualified image name to import." } }, + "sourceRegistryUsername": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The username for the source registry. Required if the source registry is private, or to logon to the public docker registry." + } + }, + "sourceRegistryPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "Optional. The password for the source registry. Required if the source registry is private, or to logon to the public docker registry." + } + }, "newImageName": { "type": "string", - "defaultValue": "[last(split(parameters('image'), '/'))]", + "defaultValue": "[string(skip(parameters('image'), add(indexOf(parameters('image'), '/'), 1)))]", "metadata": { "example": "your-image-name:tag", "description": "Optional. The new image name in the ACR. You can use this to import a publically available image with a custom name for later updating from e.g., your build pipeline." @@ -289,7 +307,7 @@ "value": "[parameters('runOnce')]" }, "azCliVersion": { - "value": "2.61.0" + "value": "2.63.0" }, "timeout": { "value": "PT30M" @@ -298,38 +316,44 @@ "value": "PT1H" }, "environmentVariables": { - "value": { - "secureList": [ - { - "name": "acrName", - "value": "[parameters('acrName')]" - }, - { - "name": "imageName", - "value": "[parameters('image')]" - }, - { - "name": "newImageName", - "value": "[parameters('newImageName')]" - }, - { - "name": "overwriteExistingImage", - "value": "[toLower(string(parameters('overwriteExistingImage')))]" - }, - { - "name": "initialDelay", - "value": "[format('{0}s', string(parameters('initialScriptDelay')))]" - }, - { - "name": "retryMax", - "value": "[string(parameters('retryMax'))]" - }, - { - "name": "retrySleep", - "value": "5s" - } - ] - } + "value": [ + { + "name": "acrName", + "value": "[parameters('acrName')]" + }, + { + "name": "imageName", + "value": "[parameters('image')]" + }, + { + "name": "newImageName", + "value": "[parameters('newImageName')]" + }, + { + "name": "overwriteExistingImage", + "value": "[toLower(string(parameters('overwriteExistingImage')))]" + }, + { + "name": "initialDelay", + "value": "[format('{0}s', string(parameters('initialScriptDelay')))]" + }, + { + "name": "retryMax", + "value": "[string(parameters('retryMax'))]" + }, + { + "name": "retrySleep", + "value": "5s" + }, + { + "name": "sourceRegistryUsername", + "value": "[parameters('sourceRegistryUsername')]" + }, + { + "name": "sourceRegistryPassword", + "secureValue": "[parameters('sourceRegistryPassword')]" + } + ] }, "cleanupPreference": { "value": "[parameters('cleanupPreference')]" @@ -344,7 +368,7 @@ "value": "[parameters('subnetResourceIds')]" }, "scriptContent": { - "value": "#!/bin/bash\n set -e\n\n echo \"Waiting on RBAC replication ($initialDelay)\\n\"\n sleep $initialDelay\n\n # retry loop to catch errors (usually RBAC delays, but 'Error copying blobs' is also not unheard of)\n retryLoopCount=0\n until [ $retryLoopCount -ge $retryMax ]\n do\n echo \"Importing Image ($retryLoopCount): $imageName into ACR: $acrName\\n\"\n if [ $overwriteExistingImage = 'true' ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --force\n else\n az acr import -n $acrName --source $imageName --image $newImageName\n fi\n\n sleep $retrySleep\n retryLoopCount=$((retryLoopCount+1))\n done\n\n echo \"done\\n\"" + "value": "#!/bin/bash\n echo \"Waiting on RBAC replication ($initialDelay)\\n\"\n sleep $initialDelay\n\n # retry loop to catch errors (usually RBAC delays, but 'Error copying blobs' is also not unheard of)\n retryLoopCount=0\n until [ $retryLoopCount -ge $retryMax ]\n do\n echo \"Importing Image ($retryLoopCount): $imageName into ACR: $acrName\\n\"\n if [ $overwriteExistingImage = 'true' ]; then\n if [ -n \"$sourceRegistryUsername\" ] && [ -n \"$sourceRegistryPassword\" ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --force --username $sourceRegistryUsername --password $sourceRegistryPassword\n else\n az acr import -n $acrName --source $imageName --image $newImageName --force\n fi\n else\n if [ -n \"$sourceRegistryUsername\" ] && [ -n \"$sourceRegistryPassword\" ]; then\n az acr import -n $acrName --source $imageName --image $newImageName --username $sourceRegistryUsername --password $sourceRegistryPassword\n else\n az acr import -n $acrName --source $imageName --image $newImageName\n fi\n fi\n\n sleep $retrySleep\n retryLoopCount=$((retryLoopCount+1))\n done\n\n echo \"done\\n\"" } }, "template": { @@ -354,8 +378,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "148060868388125113" + "version": "0.29.47.4906", + "templateHash": "5978422939896103340" }, "name": "Deployment Scripts", "description": "This module deploys Deployment Scripts.", @@ -407,6 +431,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -469,32 +500,29 @@ "nullable": true }, "environmentVariableType": { - "type": "secureObject", + "type": "object", "properties": { - "secureList": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "secureValue": { - "type": "string", - "nullable": true - }, - "value": { - "type": "string", - "nullable": true - } - } - }, + "name": { + "type": "string", "metadata": { - "description": "Optional. The list of environment variables to pass over to the deployment script." + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Required. The value of the secure environment variable." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The value of the environment variable." } } - }, - "nullable": true + } } }, "parameters": { @@ -564,9 +592,13 @@ } }, "environmentVariables": { - "$ref": "#/definitions/environmentVariableType", + "type": "array", + "items": { + "$ref": "#/definitions/environmentVariableType" + }, + "nullable": true, "metadata": { - "description": "Optional. The environment variables to pass over to the script. The list is passed as an object with a key name \"secureList\" and the value is the list of environment variables (array). The list must have a 'name' and a 'value' or a 'secretValue' property for each object." + "description": "Optional. The environment variables to pass over to the script." } }, "supportingScriptUris": { @@ -595,7 +627,7 @@ }, "retentionInterval": { "type": "string", - "nullable": true, + "defaultValue": "P1D", "metadata": { "description": "Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week)." } @@ -669,6 +701,11 @@ }, "variables": { "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, { "name": "subnetIds", "count": "[length(coalesce(parameters('subnetResourceIds'), createArray()))]", @@ -681,7 +718,7 @@ "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" }, "containerSettings": { @@ -705,7 +742,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.2.3', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -735,7 +772,7 @@ "containerSettings": "[if(not(empty(variables('containerSettings'))), variables('containerSettings'), null())]", "storageAccountSettings": "[if(not(empty(parameters('storageAccountResourceId'))), if(not(empty(parameters('storageAccountResourceId'))), createObject('storageAccountKey', if(empty(parameters('subnetResourceIds')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2], split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))), '2023-01-01').keys[0].value, null()), 'storageAccountName', last(split(parameters('storageAccountResourceId'), '/'))), null()), null())]", "arguments": "[parameters('arguments')]", - "environmentVariables": "[if(not(equals(parameters('environmentVariables'), null())), parameters('environmentVariables').secureList, createArray())]", + "environmentVariables": "[parameters('environmentVariables')]", "scriptContent": "[if(not(empty(parameters('scriptContent'))), parameters('scriptContent'), null())]", "primaryScriptUri": "[if(not(empty(parameters('primaryScriptUri'))), parameters('primaryScriptUri'), null())]", "supportingScriptUris": "[if(not(empty(parameters('supportingScriptUris'))), parameters('supportingScriptUris'), null())]", @@ -765,20 +802,20 @@ "deploymentScript_roleAssignments": { "copy": { "name": "deploymentScript_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "deploymentScript" @@ -828,7 +865,7 @@ "metadata": { "description": "The output of the deployment script." }, - "value": "[if(contains(reference('deploymentScript'), 'outputs'), reference('deploymentScript').outputs, createObject())]" + "value": "[coalesce(tryGet(reference('deploymentScript'), 'outputs'), createObject())]" }, "deploymentScriptLogs": { "type": "array", @@ -873,7 +910,7 @@ }, "value": { "originalImage": "[parameters('image')]", - "acrHostedImage": "[format('{0}{1}', reference('acr').loginServer, string(skip(parameters('image'), indexOf(parameters('image'), '/'))))]" + "acrHostedImage": "[if(empty(parameters('newImageName')), format('{0}{1}', reference('acr').loginServer, string(skip(parameters('image'), indexOf(parameters('image'), '/')))), format('{0}/{1}', reference('acr').loginServer, parameters('newImageName')))]" } } } diff --git a/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/dependencies.bicep b/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/dependencies.bicep index c66f2f19c2..f68b4451d5 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/dependencies.bicep +++ b/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/dependencies.bicep @@ -13,6 +13,9 @@ param acrName string @description('Required. The name of the Storage Account to create.') param storageAccountName string +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + var ipRange = '10.0.0.0' module identity 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.1' = { @@ -105,6 +108,52 @@ module storage 'br/public:avm/res/storage/storage-account:0.9.0' = { } } +// KeyVault stores the password to login to the source container registry +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: null + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + dependsOn: [identity] + + resource containerRegistrySecret 'secrets@2023-07-01' = { + name: 'ContainerRegistryPassword' + properties: { + // put the password of the source container registry here + value: '' + } + } + + resource rbac 'accessPolicies@2023-07-01' = { + name: 'add' + properties: { + accessPolicies: [ + { + tenantId: tenant().tenantId + objectId: identity.outputs.principalId + permissions: { + keys: [] + secrets: ['get', 'list', 'set'] + certificates: [] + storage: [] + } + } + ] + } + } +} + // the container registry to upload the image into module acr 'br/public:avm/res/container-registry/registry:0.2.0' = { name: '${uniqueString(resourceGroup().name, location)}-acr' @@ -145,3 +194,9 @@ output storageAccountResourceId string = storage.outputs.resourceId @description('The resource ID of the created subnet designated for the Deployment Script.') output deploymentScriptSubnetResourceId string = vnet::subnet_deploymentscript.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created Key Vault secret.') +output keyVaultSecretName string = keyVault::containerRegistrySecret.name diff --git a/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep b/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep index a00d32d62c..8cd3fd3db1 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep +++ b/avm/ptn/deployment-script/import-image-to-acr/tests/e2e/max/main.test.bicep @@ -31,6 +31,7 @@ module dependencies 'dependencies.bicep' = { virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' acrName: 'dep${namePrefix}acr${serviceShort}' storageAccountName: 'dep${namePrefix}sa${serviceShort}' + keyVaultName: 'dep${namePrefix}kv${serviceShort}' managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' } } @@ -46,6 +47,11 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { // Test Execution // // ============== // +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = { + name: last(split(dependencies.outputs.keyVaultResourceId, '/')) + scope: resourceGroup +} + @batchSize(1) module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { @@ -59,8 +65,11 @@ module testDeployment '../../../main.bicep' = [ } acrName: dependencies.outputs.acrName location: resourceLocation - image: 'mcr.microsoft.com/k8se/quickstart-jobs:latest' - newImageName: 'your-image-name:tag' + image: 'mcr.microsoft.com/k8se/quickstart-jobs:latest' // e.g. for docker images, that will be authenticated with the below properties 'docker.io/hello-world:latest' + // commented out, as the user is not available in the test environment + // sourceRegistryUsername: 'username' + // sourceRegistryPassword: keyVault.getSecret(dependencies.outputs.keyVaultSecretName) + newImageName: 'application/your-image-name:tag' cleanupPreference: 'OnExpiration' assignRbacRole: true managedIdentities: { userAssignedResourcesIds: [dependencies.outputs.managedIdentityResourceId] } diff --git a/avm/ptn/deployment-script/import-image-to-acr/version.json b/avm/ptn/deployment-script/import-image-to-acr/version.json index daf1a794d9..17dd49a0b9 100644 --- a/avm/ptn/deployment-script/import-image-to-acr/version.json +++ b/avm/ptn/deployment-script/import-image-to-acr/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/ptn/dev-ops/cicd-agents-and-runners/README.md b/avm/ptn/dev-ops/cicd-agents-and-runners/README.md index 74b97be263..0b7b19c8fe 100644 --- a/avm/ptn/dev-ops/cicd-agents-and-runners/README.md +++ b/avm/ptn/dev-ops/cicd-agents-and-runners/README.md @@ -67,14 +67,14 @@ This module deploys self-hosted agents and runners for Azure DevOps and GitHub o | `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | | `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | | `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | -| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | | `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | -| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | | `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | -| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | ## Usage examples @@ -135,7 +135,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -181,6 +181,38 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-app' + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aca' +} +param selfHostedConfig = { + agentsPoolName: 'agents-pool' + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + selfHostedType: 'azuredevops' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 2: _Using only defaults for Azure DevOps self-hosted agents using Azure Container Instances._ This instance deploys the module with the minimum set of required parameters for Azure DevOps self-hosted agents in Azure Container Instances. @@ -222,7 +254,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -267,6 +299,37 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aci' +} +param selfHostedConfig = { + agentsPoolName: 'aci-pool' + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + selfHostedType: 'azuredevops' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 3: _Using only defaults for GitHub self-hosted runners using Azure Container Apps._ This instance deploys the module with the minimum set of required parameters for GitHub self-hosted runners in Azure Container Apps. @@ -308,7 +371,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -353,6 +416,37 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-app' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aca' +} +param selfHostedConfig = { + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + selfHostedType: 'github' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 4: _Using large parameter set for Azure DevOps self-hosted agents using Azure Container Apps._ This instance deploys the module with most of its features enabled for Azure DevOps self-hosted agents using Azure Container Apps. @@ -405,7 +499,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -461,6 +555,48 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-app' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + containerAppSubnetAddressPrefix: '10.0.1.0/24' + containerAppSubnetName: 'acaSubnet' + networkType: 'createNew' + virtualNetworkName: 'vnet-aca' +} +param selfHostedConfig = { + agentNamePrefix: '' + agentsPoolName: 'aca-pool' + azureContainerAppTarget: { + resources: { + cpu: '1' + memory: '2Gi' + } + } + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + placeHolderAgentName: 'acaPlaceHolderAgent' + selfHostedType: 'azuredevops' + targetPipelinesQueueLength: '1' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 5: _Using large parameter set for GitHub self-hosted runners using Azure Container Instances._ This instance deploys the module with most of its features enabled for GitHub self-hosted runners using Azure Container Instances. @@ -514,7 +650,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -571,6 +707,49 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + containerInstanceSubnetAddressPrefix: '10.0.1.0/24' + containerInstanceSubnetName: 'aci-subnet' + networkType: 'createNew' + virtualNetworkName: 'vnet-aci' +} +param selfHostedConfig = { + azureContainerInstanceTarget: { + cpu: 1 + memoryInGB: 2 + numberOfInstances: 3 + sku: 'Standard' + } + ephemeral: true + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + runnerNamePrefix: '' + runnerScope: 'repo' + selfHostedType: 'github' + targetWorkflowQueueLength: '1' +} +// Non-required parameters +param location = '' +param privateNetworking = false +``` + +
+

+ ### Example 6: _Using only defaults for Azure DevOps self-hosted agents using Private networking in an existing vnet._ This instance deploys the module with the minimum set of required parameters Azure DevOps self-hosted agents using Private networking in Azure Container Instances in an existing vnet. @@ -623,7 +802,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -679,6 +858,48 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + computeNetworking: { + computeNetworkType: 'azureContainerInstance' + containerInstanceSubnetName: 'aci-subnet' + } + containerRegistryPrivateDnsZoneResourceId: '' + containerRegistryPrivateEndpointSubnetName: 'acr-subnet' + natGatewayPublicIpAddressResourceId: '' + natGatewayResourceId: '' + networkType: 'useExisting' + virtualNetworkResourceId: '' +} +param selfHostedConfig = { + agentNamePrefix: '' + agentsPoolName: 'aci-pool' + azureContainerInstanceTarget: { + numberOfInstances: 2 + } + devOpsOrganization: 'azureDevOpsOrganization' + personalAccessToken: '' + selfHostedType: 'azuredevops' +} +// Non-required parameters +param location = '' +param privateNetworking = true +``` + +
+

+ ### Example 7: _Using only defaults for GitHub self-hosted runners using Private networking in an existing vnet._ This instance deploys the module with the minimum set of required parameters GitHub self-hosted runners using Private networking in Azure Container Apps in an existing vnet. @@ -730,7 +951,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -785,6 +1006,47 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + computeNetworking: { + computeNetworkType: 'azureContainerApp' + containerAppDeploymentScriptSubnetName: 'aca-ds-subnet' + containerAppSubnetName: 'aca-subnet' + containerInstanceSubnetName: 'aci-subnet' + deploymentScriptPrivateDnsZoneResourceId: '' + } + containerRegistryPrivateDnsZoneResourceId: '' + containerRegistryPrivateEndpointSubnetName: 'acr-subnet' + natGatewayPublicIpAddressResourceId: '' + natGatewayResourceId: '' + networkType: 'useExisting' + virtualNetworkResourceId: '' +} +param selfHostedConfig = { + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + selfHostedType: 'github' +} +// Non-required parameters +param location = '' +param privateNetworking = true +``` + +
+

+ ### Example 8: _Using only defaults for GitHub self-hosted runners using Private networking._ This instance deploys the module with the minimum set of required parameters GitHub self-hosted runners using Private networking in Azure Container Instances. @@ -826,7 +1088,7 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

-via JSON Parameter file +via JSON parameters file ```json { @@ -871,6 +1133,37 @@ module cicdAgentsAndRunners 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:<

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/dev-ops/cicd-agents-and-runners:' + +// Required parameters +param computeTypes = [ + 'azure-container-instance' +] +param namingPrefix = '' +param networkingConfiguration = { + addressSpace: '10.0.0.0/16' + networkType: 'createNew' + virtualNetworkName: 'vnet-aci' +} +param selfHostedConfig = { + githubOrganization: 'githHubOrganization' + githubRepository: 'dummyRepo' + personalAccessToken: '' + selfHostedType: 'github' +} +// Non-required parameters +param location = '' +param privateNetworking = true +``` + +
+

+ ## Parameters **Required parameters** diff --git a/avm/ptn/finops-toolkit/finops-hub/README.md b/avm/ptn/finops-toolkit/finops-hub/README.md index 8458506c7d..4abb463210 100644 --- a/avm/ptn/finops-toolkit/finops-hub/README.md +++ b/avm/ptn/finops-toolkit/finops-hub/README.md @@ -80,7 +80,7 @@ module finopsHub 'br/public:avm/ptn/finops-toolkit/finops-hub:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -102,6 +102,22 @@ module finopsHub 'br/public:avm/ptn/finops-toolkit/finops-hub:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/finops-toolkit/finops-hub:' + +// Required parameters +param hubName = 'finops-hub-finmin' +// Non-required parameters +param location = '' +``` + +
+

+ ## Parameters **Optional parameters** diff --git a/avm/ptn/lz/sub-vending/README.md b/avm/ptn/lz/sub-vending/README.md index d765a73bfc..c5abe03e9f 100644 --- a/avm/ptn/lz/sub-vending/README.md +++ b/avm/ptn/lz/sub-vending/README.md @@ -25,9 +25,9 @@ This module deploys a subscription to accelerate deployment of landing zones. Fo | `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Network/virtualHubs/hubVirtualNetworkConnections` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualHubs/hubVirtualNetworkConnections) | -| `Microsoft.Network/virtualNetworks` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks) | -| `Microsoft.Network/virtualNetworks/subnets` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks/subnets) | -| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks/virtualNetworkPeerings) | +| `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | | `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2023-08-01/deploymentScripts) | | `Microsoft.Resources/resourceGroups` | [2021-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2021-04-01/resourceGroups) | | `Microsoft.Resources/tags` | [2019-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/tags) | @@ -35,14 +35,14 @@ This module deploys a subscription to accelerate deployment of landing zones. Fo | `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | | `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | | `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | -| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | | `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | -| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | | `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | -| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | | `Microsoft.Subscription/aliases` | [2021-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Subscription/2021-10-01/aliases) | ## Usage examples @@ -91,7 +91,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -135,6 +135,30 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/lz/sub-vending:' + +param resourceProviders = {} +param subscriptionAliasEnabled = true +param subscriptionAliasName = '' +param subscriptionBillingScope = '' +param subscriptionDisplayName = '' +param subscriptionManagementGroupAssociationEnabled = true +param subscriptionManagementGroupId = 'bicep-lz-vending-automation-child' +param subscriptionTags = { + namePrefix: '' + serviceShort: '' +} +param subscriptionWorkload = 'Production' +``` + +
+

+ ### Example 2: _Hub and spoke topology._ This instance deploys a subscription with a hub-spoke network topology. @@ -202,7 +226,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -315,6 +339,63 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/lz/sub-vending:' + +param deploymentScriptLocation = '' +param deploymentScriptManagedIdentityName = '' +param deploymentScriptName = 'ds-ssahs' +param deploymentScriptNetworkSecurityGroupName = '' +param deploymentScriptResourceGroupName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptVirtualNetworkName = '' +param hubNetworkResourceId = '' +param resourceProviders = { + 'Microsoft.AVS': [ + 'AzureServicesVm' + ] + 'Microsoft.HybridCompute': [ + 'ArcServerPrivateLinkPreview' + ] +} +param roleAssignmentEnabled = true +param roleAssignments = [ + { + definition: '/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7' + principalId: '896b1162-be44-4b28-888a-d01acc1b4271' + relativeScope: '' + } +] +param subscriptionAliasEnabled = true +param subscriptionAliasName = '' +param subscriptionBillingScope = '' +param subscriptionDisplayName = '' +param subscriptionManagementGroupAssociationEnabled = true +param subscriptionManagementGroupId = 'bicep-lz-vending-automation-child' +param subscriptionTags = { + namePrefix: '' + serviceShort: '' +} +param subscriptionWorkload = 'Production' +param virtualNetworkAddressSpace = [ + '10.110.0.0/16' +] +param virtualNetworkEnabled = true +param virtualNetworkLocation = '' +param virtualNetworkName = '' +param virtualNetworkPeeringEnabled = true +param virtualNetworkResourceGroupLockEnabled = false +param virtualNetworkResourceGroupName = '' +param virtualNetworkUseRemoteGateways = false +``` + +
+

+ ### Example 3: _Vwan topology._ This instance deploys a subscription with a vwan network topology. @@ -374,7 +455,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

-via JSON Parameter file +via JSON parameters file ```json { @@ -477,6 +558,55 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = {

+

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/lz/sub-vending:' + +param deploymentScriptLocation = '' +param deploymentScriptManagedIdentityName = '' +param deploymentScriptName = 'ds-ssawan' +param deploymentScriptNetworkSecurityGroupName = '' +param deploymentScriptResourceGroupName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptVirtualNetworkName = '' +param hubNetworkResourceId = '' +param resourceProviders = {} +param roleAssignmentEnabled = true +param roleAssignments = [ + { + definition: '/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7' + principalId: '896b1162-be44-4b28-888a-d01acc1b4271' + relativeScope: '' + } +] +param subscriptionAliasEnabled = true +param subscriptionAliasName = '' +param subscriptionBillingScope = '' +param subscriptionDisplayName = '' +param subscriptionManagementGroupAssociationEnabled = true +param subscriptionManagementGroupId = 'bicep-lz-vending-automation-child' +param subscriptionTags = { + namePrefix: '' + serviceShort: '' +} +param subscriptionWorkload = 'Production' +param virtualNetworkAddressSpace = [ + '10.210.0.0/16' +] +param virtualNetworkEnabled = true +param virtualNetworkLocation = '' +param virtualNetworkName = '' +param virtualNetworkPeeringEnabled = true +param virtualNetworkResourceGroupLockEnabled = false +param virtualNetworkResourceGroupName = '' +``` + +
+

+ ## Parameters **Optional parameters** @@ -493,6 +623,7 @@ module subVending 'br/public:avm/ptn/lz/sub-vending:' = { | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`existingSubscriptionId`](#parameter-existingsubscriptionid) | string | An existing subscription ID. Use this when you do not want the module to create a new subscription. But do want to manage the management group membership. A subscription ID should be provided in the example format `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`. | | [`hubNetworkResourceId`](#parameter-hubnetworkresourceid) | string | The resource ID of the Virtual Network or Virtual WAN Hub in the hub to which the created Virtual Network, by this module, will be peered/connected to via Virtual Network Peering or a Virtual WAN Virtual Hub Connection.

| +| [`managementGroupAssociationDelayCount`](#parameter-managementgroupassociationdelaycount) | int | The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur. | | [`resourceProviders`](#parameter-resourceproviders) | object | An object of resource providers and resource providers features to register. If left blank/empty, no resource providers will be registered.

| | [`roleAssignmentEnabled`](#parameter-roleassignmentenabled) | bool | Whether to create role assignments or not. If true, supply the array of role assignment objects in the parameter called `roleAssignments`.

| | [`roleAssignments`](#parameter-roleassignments) | array | Supply an array of objects containing the details of the role assignments to create.

Each object must contain the following `keys`:

  • `principalId` = The Object ID of the User, Group, SPN, Managed Identity to assign the RBAC role too.
  • `definition` = The Name of one of the pre-defined built-In RBAC Roles or a Resource ID of a Built-in or custom RBAC Role Definition as follows:

    - You can only provide the RBAC role name of the pre-defined roles (Contributor, Owner, Reader, Role Based Access Control Administrator (Preview), and User Access Administrator). We only provide those roles as they are the most common ones to assign to a new subscription, also to reduce the template size and complexity in case we define each and every Built-in RBAC role.

    - You can provide the Resource ID of a Built-in or custom RBAC Role Definition

    - e.g. `/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`

  • `relativeScope` = 2 options can be provided for input value:

    1. `''` *(empty string)* = Make RBAC Role Assignment to Subscription scope

    2. `'/resourceGroups/'` = Make RBAC Role Assignment to specified Resource Group.

    | @@ -605,6 +736,14 @@ The resource ID of the Virtual Network or Virtual WAN Hub in the hub to which th - Type: string - Default: `''` +### Parameter: `managementGroupAssociationDelayCount` + +The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur. + +- Required: No +- Type: int +- Default: `15` + ### Parameter: `resourceProviders` An object of resource providers and resource providers features to register. If left blank/empty, no resource providers will be registered.

    @@ -949,7 +1088,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | `br/public:avm/ptn/authorization/role-assignment:0.1.0` | Remote reference | | `br/public:avm/res/managed-identity/user-assigned-identity:0.2.2` | Remote reference | | `br/public:avm/res/network/network-security-group:0.3.0` | Remote reference | -| `br/public:avm/res/network/virtual-network:0.1.7` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | | `br/public:avm/res/resources/deployment-script:0.2.3` | Remote reference | | `br/public:avm/res/resources/resource-group:0.2.4` | Remote reference | | `br/public:avm/res/storage/storage-account:0.9.1` | Remote reference | diff --git a/avm/ptn/lz/sub-vending/main.bicep b/avm/ptn/lz/sub-vending/main.bicep index dd26bc28a1..62f27ca2c3 100644 --- a/avm/ptn/lz/sub-vending/main.bicep +++ b/avm/ptn/lz/sub-vending/main.bicep @@ -297,6 +297,9 @@ param resourceProviders object = { 'Microsoft.Web': [] } +@sys.description('Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur.') +param managementGroupAssociationDelayCount int = 15 + // VARIABLES var existingSubscriptionIDEmptyCheck = empty(existingSubscriptionId) @@ -355,6 +358,7 @@ module createSubscriptionResources './modules/subResourceWrapper.bicep' = if (su subscriptionId: (subscriptionAliasEnabled && empty(existingSubscriptionId)) ? createSubscription.outputs.subscriptionId : existingSubscriptionId + managementGroupAssociationDelayCount: managementGroupAssociationDelayCount subscriptionManagementGroupAssociationEnabled: subscriptionManagementGroupAssociationEnabled subscriptionManagementGroupId: subscriptionManagementGroupId subscriptionTags: subscriptionTags diff --git a/avm/ptn/lz/sub-vending/main.json b/avm/ptn/lz/sub-vending/main.json index 7d14c11f82..ee24f61ead 100644 --- a/avm/ptn/lz/sub-vending/main.json +++ b/avm/ptn/lz/sub-vending/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "11010234208010675398" + "version": "0.30.23.60470", + "templateHash": "2644636658214532574" }, "name": "Sub-vending", "description": "This module deploys a subscription to accelerate deployment of landing zones. For more information on how to use it, please visit this [Wiki](https://github.com/Azure/bicep-lz-vending/wiki).", @@ -377,6 +377,13 @@ "metadata": { "description": "Optional. An object of resource providers and resource providers features to register. If left blank/empty, no resource providers will be registered.\n" } + }, + "managementGroupAssociationDelayCount": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur." + } } }, "variables": { @@ -445,8 +452,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "3306118610933947345" + "version": "0.30.23.60470", + "templateHash": "1611270751895734589" } }, "parameters": { @@ -546,6 +553,9 @@ "mode": "Incremental", "parameters": { "subscriptionId": "[if(and(parameters('subscriptionAliasEnabled'), empty(parameters('existingSubscriptionId'))), createObject('value', reference(extensionResourceId(managementGroup().id, 'Microsoft.Resources/deployments', variables('deploymentNames').createSubscription), '2022-09-01').outputs.subscriptionId.value), createObject('value', parameters('existingSubscriptionId')))]", + "managementGroupAssociationDelayCount": { + "value": "[parameters('managementGroupAssociationDelayCount')]" + }, "subscriptionManagementGroupAssociationEnabled": { "value": "[parameters('subscriptionManagementGroupAssociationEnabled')]" }, @@ -652,8 +662,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "15097801658394168144" + "version": "0.30.23.60470", + "templateHash": "2549730186599602050" }, "name": "`/subResourcesWrapper/deploy.bicep` Parameters", "description": "This module is used by the [`bicep-lz-vending`](https://aka.ms/sub-vending/bicep) module to help orchestrate the deployment", @@ -960,11 +970,19 @@ "metadata": { "description": "The name of the storage account for the deployment script." } + }, + "managementGroupAssociationDelayCount": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur." + } } }, "variables": { - "$fxv#0": "Param(\n[string]$subscriptionId,\n[string]$resourceProviders\n)\n\n$ErrorActionPreference = 'SilentlyContinue'\n# Selecting the right subscription\nSelect-AzSubscription -SubscriptionId $subscriptionId\n\n# Defining variables\n$providers = $resourceProviders | ConvertFrom-Json -AsHashtable\n$failedProviders = ''\n$failedFeatures = ''\n$DeploymentScriptOutputs = @{}\n\n##############################################\n## Registering resource providers and features\n##############################################\n\nif ($providers.Count -gt 0) {\n foreach ($provider in $providers.keys) {\n try {\n # Registering resource providers\n $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState\n # Check if the providered is registered\n if ($providerStatus -eq 'NotRegistered') {\n Write-Output \"`n Registering the '$provider' provider\"\n if (Register-AzResourceProvider -ProviderNamespace $provider) {\n Write-Output \"`n The registration for provider'$provider' has started successfully\"\n } else {\n Write-Output \"`n The '$provider' provider has not been registered successfully\"\n $failedProviders += \",$provider\"\n }\n } elseif ($providerStatus -eq 'Registering') {\n Write-Output \"`n The '$provider' provider is in registering state\"\n $failedProviders += \",$provider\"\n } elseif ( $null -eq $providerStatus) {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n }\n\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n }\n # Registering resource providers features\n $features = $providers[$provider]\n if ($features.length -gt 0) {\n foreach ($feature in $features) {\n try {\n # Define variables\n $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState\n # Check if the feature is registered\n if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') {\n Write-Output \"`n Registering the '$feature' feature\"\n if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) {\n Write-Output \"`n The The registration for feature '$feature' has started successfully\"\n } else {\n Write-Output \"`n The '$feature' feature has not been registered successfully\"\n $failedFeatures += \",$feature\"\n }\n } elseif ($null -eq $featureStatus) {\n Write-Output \"`n The '$feature' feature doesn't exist.\"\n $failedFeatures += \",$feature\"\n }\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid\"\n $failedFeatures += \",$feature\"\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n } else {\n $output = 'No failures'\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n} else {\n Write-Output \"`n No providers or features to register\"\n}\n", + "$fxv#0": "Param(\n [string]$subscriptionId,\n [string]$resourceProviders\n)\n\n$ErrorActionPreference = 'SilentlyContinue'\n# Selecting the right subscription\nSelect-AzSubscription -SubscriptionId $subscriptionId\n\n# Defining variables\n$providers = $resourceProviders | ConvertFrom-Json -AsHashtable\n$failedProviders = ''\n$failedFeatures = ''\n$DeploymentScriptOutputs = @{}\n\n##############################################\n## Registering resource providers and features\n##############################################\n\nif ($providers.Count -gt 0) {\n foreach ($provider in $providers.keys) {\n try {\n # Registering resource providers\n $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState\n # Check if the providered is registered\n if ($providerStatus -eq 'NotRegistered') {\n Write-Output \"`n Registering the '$provider' provider\"\n if (Register-AzResourceProvider -ProviderNamespace $provider) {\n Write-Output \"`n The registration for provider'$provider' has started successfully\"\n } else {\n Write-Output \"`n The '$provider' provider has not been registered successfully\"\n $failedProviders += \",$provider\"\n }\n } elseif ($providerStatus -eq 'Registering') {\n Write-Output \"`n The '$provider' provider is in registering state\"\n $failedProviders += \",$provider\"\n } elseif ( $null -eq $providerStatus) {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n }\n\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid\"\n $failedProviders += \",$provider\"\n if ($failedProviders.length -gt 0) {\n $output = $failedProviders.substring(1)\n }\n $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output\n }\n # Registering resource providers features\n $features = $providers[$provider]\n if ($features.length -gt 0) {\n foreach ($feature in $features) {\n try {\n # Define variables\n $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState\n # Check if the feature is registered\n if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') {\n Write-Output \"`n Registering the '$feature' feature\"\n if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) {\n Write-Output \"`n The The registration for feature '$feature' has started successfully\"\n } else {\n Write-Output \"`n The '$feature' feature has not been registered successfully\"\n $failedFeatures += \",$feature\"\n }\n } elseif ($null -eq $featureStatus) {\n Write-Output \"`n The '$feature' feature doesn't exist.\"\n $failedFeatures += \",$feature\"\n }\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n } else {\n $output = 'No failures'\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n } catch {\n Write-Output \"`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid\"\n $failedFeatures += \",$feature\"\n if ($failedFeatures.length -gt 0) {\n $output = $failedFeatures.substring(1)\n }\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n } else {\n $output = 'No failures'\n $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output\n }\n }\n} else {\n Write-Output \"`n No providers or features to register\"\n}\n", "deploymentNames": { + "moveSubscriptionToManagementGroupDelay": "[take(format('lz-vend-move-sub-delay-{0}', uniqueString(parameters('subscriptionId'), parameters('subscriptionManagementGroupId'), deployment().name)), 64)]", "moveSubscriptionToManagementGroup": "[take(format('lz-vend-move-sub-{0}', uniqueString(parameters('subscriptionId'), parameters('subscriptionManagementGroupId'), deployment().name)), 64)]", "tagSubscription": "[take(format('lz-vend-tag-sub-{0}', uniqueString(parameters('subscriptionId'), deployment().name)), 64)]", "createResourceGroupForLzNetworking": "[take(format('lz-vend-rsg-create-{0}', uniqueString(parameters('subscriptionId'), parameters('virtualNetworkResourceGroupName'), parameters('virtualNetworkLocation'), deployment().name)), 64)]", @@ -992,7 +1010,7 @@ "virtualWanHubName": "[if(not(empty(variables('virtualHubResourceIdChecked'))), split(variables('virtualHubResourceIdChecked'), '/')[8], '')]", "virtualWanHubSubscriptionId": "[if(not(empty(variables('virtualHubResourceIdChecked'))), split(variables('virtualHubResourceIdChecked'), '/')[2], '')]", "virtualWanHubResourceGroupName": "[if(not(empty(variables('virtualHubResourceIdChecked'))), split(variables('virtualHubResourceIdChecked'), '/')[4], '')]", - "virtualWanHubConnectionName": "[format('vhc-{0}', guid(variables('virtualHubResourceIdChecked'), parameters('virtualNetworkName'), parameters('virtualNetworkResourceGroupName'), parameters('virtualNetworkLocation'), parameters('subscriptionId')))]", + "virtualWanHubConnectionName": "[format('vhc-{0}-{1}', parameters('virtualNetworkName'), substring(guid(variables('virtualHubResourceIdChecked'), parameters('virtualNetworkName'), parameters('virtualNetworkResourceGroupName'), parameters('virtualNetworkLocation'), parameters('subscriptionId')), 0, 5))]", "virtualWanHubConnectionAssociatedRouteTable": "[if(not(empty(parameters('virtualNetworkVwanAssociatedRouteTableResourceId'))), parameters('virtualNetworkVwanAssociatedRouteTableResourceId'), format('{0}/hubRouteTables/defaultRouteTable', variables('virtualHubResourceIdChecked')))]", "virutalWanHubDefaultRouteTableId": { "id": "[format('{0}/hubRouteTables/defaultRouteTable', variables('virtualHubResourceIdChecked'))]" @@ -1002,6 +1020,27 @@ "resourceProvidersFormatted": "[replace(string(parameters('resourceProviders')), '\"', '\\\"')]" }, "resources": [ + { + "copy": { + "name": "moveSubscriptionToManagementGroupDelay", + "count": "[length(range(0, parameters('managementGroupAssociationDelayCount')))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[and(parameters('subscriptionManagementGroupAssociationEnabled'), not(empty(parameters('subscriptionManagementGroupId'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('{0}-{1}', variables('deploymentNames').moveSubscriptionToManagementGroupDelay, copyIndex())]", + "location": "[parameters('virtualNetworkLocation')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + }, { "condition": "[and(parameters('subscriptionManagementGroupAssociationEnabled'), not(empty(parameters('subscriptionManagementGroupId'))))]", "type": "Microsoft.Resources/deployments", @@ -1028,8 +1067,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "9313475896614087193" + "version": "0.30.23.60470", + "templateHash": "15074465703139369012" } }, "parameters": { @@ -1055,7 +1094,10 @@ } ] } - } + }, + "dependsOn": [ + "moveSubscriptionToManagementGroupDelay" + ] }, { "condition": "[not(empty(parameters('subscriptionTags')))]", @@ -1086,8 +1128,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "15181721731905574940" + "version": "0.30.23.60470", + "templateHash": "15410141635305926698" } }, "parameters": { @@ -1146,8 +1188,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "2065450289597496523" + "version": "0.30.23.60470", + "templateHash": "5472979603320584709" } }, "parameters": { @@ -1202,8 +1244,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "4876221897054252048" + "version": "0.30.23.60470", + "templateHash": "11343593259864722989" } }, "parameters": { @@ -1222,7 +1264,7 @@ "metadata": { "description": "Tags currently applied to the subscription level" }, - "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), reference(subscriptionResourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01').tags, createObject())]" + "value": "[coalesce(tryGet(reference(subscriptionResourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), createObject())]" } } } @@ -1280,8 +1322,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "10772346649778391302" + "version": "0.30.23.60470", + "templateHash": "13884963778440627255" } }, "parameters": { @@ -1335,8 +1377,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "943757300004366392" + "version": "0.30.23.60470", + "templateHash": "4428652978548820109" } }, "parameters": { @@ -1355,7 +1397,7 @@ "metadata": { "description": "Tags currently applied to the subscription level" }, - "value": "[if(contains(reference(resourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), reference(resourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01').tags, createObject())]" + "value": "[coalesce(tryGet(reference(resourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), createObject())]" } } } @@ -1915,8 +1957,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "15181721731905574940" + "version": "0.30.23.60470", + "templateHash": "15410141635305926698" } }, "parameters": { @@ -1975,8 +2017,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "2065450289597496523" + "version": "0.30.23.60470", + "templateHash": "5472979603320584709" } }, "parameters": { @@ -2031,8 +2073,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "4876221897054252048" + "version": "0.30.23.60470", + "templateHash": "11343593259864722989" } }, "parameters": { @@ -2051,7 +2093,7 @@ "metadata": { "description": "Tags currently applied to the subscription level" }, - "value": "[if(contains(reference(subscriptionResourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), reference(subscriptionResourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01').tags, createObject())]" + "value": "[coalesce(tryGet(reference(subscriptionResourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), createObject())]" } } } @@ -2109,8 +2151,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "10772346649778391302" + "version": "0.30.23.60470", + "templateHash": "13884963778440627255" } }, "parameters": { @@ -2164,8 +2206,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "943757300004366392" + "version": "0.30.23.60470", + "templateHash": "4428652978548820109" } }, "parameters": { @@ -2184,7 +2226,7 @@ "metadata": { "description": "Tags currently applied to the subscription level" }, - "value": "[if(contains(reference(resourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), reference(resourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01').tags, createObject())]" + "value": "[coalesce(tryGet(reference(resourceId('Microsoft.Resources/tags', parameters('name')), '2019-10-01'), 'tags'), createObject())]" } } } @@ -2285,7 +2327,7 @@ "ddosProtectionPlanResourceId": { "value": "[parameters('virtualNetworkDdosPlanResourceId')]" }, - "peerings": "[if(and(and(and(and(and(and(parameters('virtualNetworkEnabled'), parameters('virtualNetworkPeeringEnabled')), not(empty(variables('hubVirtualNetworkResourceIdChecked')))), not(empty(parameters('virtualNetworkName')))), not(empty(parameters('virtualNetworkAddressSpace')))), not(empty(parameters('virtualNetworkLocation')))), not(empty(parameters('virtualNetworkResourceGroupName')))), createObject('value', createArray(createObject('allowForwardedTraffic', true(), 'allowVirtualNetworkAccess', true(), 'allowGatewayTransit', false(), 'useRemoteGateways', parameters('virtualNetworkUseRemoteGateways'), 'remotePeeringEnabled', parameters('virtualNetworkPeeringEnabled'), 'remoteVirtualNetworkId', variables('hubVirtualNetworkResourceIdChecked'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringAllowGatewayTransit', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', createArray()))]", + "peerings": "[if(and(and(and(and(and(and(parameters('virtualNetworkEnabled'), parameters('virtualNetworkPeeringEnabled')), not(empty(variables('hubVirtualNetworkResourceIdChecked')))), not(empty(parameters('virtualNetworkName')))), not(empty(parameters('virtualNetworkAddressSpace')))), not(empty(parameters('virtualNetworkLocation')))), not(empty(parameters('virtualNetworkResourceGroupName')))), createObject('value', createArray(createObject('remoteVirtualNetworkResourceId', variables('hubVirtualNetworkResourceIdChecked'), 'allowForwardedTraffic', true(), 'allowVirtualNetworkAccess', true(), 'allowGatewayTransit', false(), 'useRemoteGateways', parameters('virtualNetworkUseRemoteGateways'), 'remotePeeringEnabled', parameters('virtualNetworkPeeringEnabled'), 'remotePeeringAllowForwardedTraffic', true(), 'remotePeeringAllowVirtualNetworkAccess', true(), 'remotePeeringAllowGatewayTransit', true(), 'remotePeeringUseRemoteGateways', false()))), createObject('value', null()))]", "enableTelemetry": { "value": "[parameters('enableTelemetry')]" } @@ -2297,8 +2339,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16637670595978489426" + "version": "0.29.47.4906", + "templateHash": "15949466154563447171" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -2335,6 +2377,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -2515,6 +2564,242 @@ } }, "nullable": true + }, + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + } } }, "parameters": { @@ -2537,32 +2822,48 @@ "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." } }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, "subnets": { "type": "array", - "defaultValue": [], + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, "metadata": { "description": "Optional. An Array of subnets to deploy to the Virtual Network." } }, "dnsServers": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { "description": "Optional. DNS Servers associated to the Virtual Network." } }, "ddosProtectionPlanResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." } }, "peerings": { "type": "array", - "defaultValue": [], + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peerings configurations." + "description": "Optional. Virtual Network Peering configurations." } }, "vnetEncryption": { @@ -2622,15 +2923,29 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -2638,8 +2953,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.1.7', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2657,42 +2972,21 @@ }, "virtualNetwork": { "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "subnets", - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex('subnets')].name]", - "properties": { - "addressPrefix": "[parameters('subnets')[copyIndex('subnets')].addressPrefix]", - "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'addressPrefixes'), parameters('subnets')[copyIndex('subnets')].addressPrefixes, createArray())]", - "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'applicationGatewayIPConfigurations'), parameters('subnets')[copyIndex('subnets')].applicationGatewayIPConfigurations, createArray())]", - "delegations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'delegations'), parameters('subnets')[copyIndex('subnets')].delegations, createArray())]", - "ipAllocations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'ipAllocations'), parameters('subnets')[copyIndex('subnets')].ipAllocations, createArray())]", - "natGateway": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].natGatewayResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", - "networkSecurityGroup": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", - "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateEndpointNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateEndpointNetworkPolicies, null())]", - "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateLinkServiceNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateLinkServiceNetworkPolicies, null())]", - "routeTable": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].routeTableResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", - "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpoints'), parameters('subnets')[copyIndex('subnets')].serviceEndpoints, createArray())]", - "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpointPolicies'), parameters('subnets')[copyIndex('subnets')].serviceEndpointPolicies, createArray())]" - } - } - } - ], "addressSpace": { "addressPrefixes": "[parameters('addressPrefixes')]" }, + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]" + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" } }, "virtualNetwork_lock": { @@ -2753,20 +3047,20 @@ "virtualNetwork_roleAssignments": { "copy": { "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], 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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "virtualNetwork" @@ -2775,7 +3069,7 @@ "virtualNetwork_subnets": { "copy": { "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", "mode": "serial", "batchSize": 1 }, @@ -2792,23 +3086,50 @@ "value": "[parameters('name')]" }, "name": { - "value": "[parameters('subnets')[copyIndex()].name]" + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" }, "addressPrefix": { - "value": "[parameters('subnets')[copyIndex()].addressPrefix]" - }, - "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex()], 'addressPrefixes'), createObject('value', parameters('subnets')[copyIndex()].addressPrefixes), createObject('value', createArray()))]", - "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex()], 'applicationGatewayIPConfigurations'), createObject('value', parameters('subnets')[copyIndex()].applicationGatewayIPConfigurations), createObject('value', createArray()))]", - "delegations": "[if(contains(parameters('subnets')[copyIndex()], 'delegations'), createObject('value', parameters('subnets')[copyIndex()].delegations), createObject('value', createArray()))]", - "ipAllocations": "[if(contains(parameters('subnets')[copyIndex()], 'ipAllocations'), createObject('value', parameters('subnets')[copyIndex()].ipAllocations), createObject('value', createArray()))]", - "natGatewayResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'natGatewayResourceId'), createObject('value', parameters('subnets')[copyIndex()].natGatewayResourceId), createObject('value', ''))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('subnets')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateEndpointNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateEndpointNetworkPolicies), createObject('value', ''))]", - "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateLinkServiceNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateLinkServiceNetworkPolicies), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('subnets')[copyIndex()], 'roleAssignments'), createObject('value', parameters('subnets')[copyIndex()].roleAssignments), createObject('value', createArray()))]", - "routeTableResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'routeTableResourceId'), createObject('value', parameters('subnets')[copyIndex()].routeTableResourceId), createObject('value', ''))]", - "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpointPolicies'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpointPolicies), createObject('value', createArray()))]", - "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpoints'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpoints), createObject('value', createArray()))]" + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2817,8 +3138,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "9634407864982934565" + "version": "0.29.47.4906", + "templateHash": "5699372618313647761" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -2830,6 +3151,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -2896,7 +3224,7 @@ "name": { "type": "string", "metadata": { - "description": "Optional. The Name of the subnet resource." + "description": "Requird. The Name of the subnet resource." } }, "virtualNetworkName": { @@ -2907,41 +3235,45 @@ }, "addressPrefix": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The address prefix for the subnet." + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." } }, "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, "routeTableResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the route table to assign to the subnet." } }, "serviceEndpoints": { "type": "array", + "items": { + "type": "string" + }, "defaultValue": [], "metadata": { "description": "Optional. The service endpoints to enable on the subnet." } }, - "delegations": { - "type": "array", - "defaultValue": [], + "delegation": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. The delegations to enable on the subnet." + "description": "Optional. The delegation to enable on the subnet." } }, "natGatewayResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." } @@ -2955,7 +3287,7 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." } }, "privateLinkServiceNetworkPolicies": { @@ -2967,28 +3299,42 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." } }, "addressPrefixes": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. List of address prefixes for the subnet." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." } }, - "ipAllocations": { + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. Array of IpAllocation which reference this subnet." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, "serviceEndpointPolicies": { @@ -3006,12 +3352,19 @@ } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -3019,26 +3372,35 @@ "virtualNetwork": { "existing": true, "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[parameters('virtualNetworkName')]" }, "subnet": { "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "serviceEndpoints": "[parameters('serviceEndpoints')]", - "delegations": "[parameters('delegations')]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", - "addressPrefixes": "[parameters('addressPrefixes')]", "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "ipAllocations": "[parameters('ipAllocations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" }, "dependsOn": [ "virtualNetwork" @@ -3047,20 +3409,20 @@ "subnet_roleAssignments": { "copy": { "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], 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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "subnet" @@ -3089,19 +3451,19 @@ }, "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" }, - "subnetAddressPrefix": { + "addressPrefix": { "type": "string", "metadata": { "description": "The address prefix for the subnet." }, - "value": "[reference('subnet').addressPrefix]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" }, - "subnetAddressPrefixes": { + "addressPrefixes": { "type": "array", "metadata": { "description": "List of address prefixes for the subnet." }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" } } } @@ -3113,7 +3475,7 @@ "virtualNetwork_peering_local": { "copy": { "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -3127,15 +3489,27 @@ "localVnetName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" }, - "name": "[if(contains(parameters('peerings')[copyIndex()], 'name'), createObject('value', parameters('peerings')[copyIndex()].name), createObject('value', format('{0}-{1}', parameters('name'), last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')))))]", - "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'allowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].allowForwardedTraffic), createObject('value', true()))]", - "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'allowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].allowGatewayTransit), createObject('value', false()))]", - "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'allowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].allowVirtualNetworkAccess), createObject('value', true()))]", - "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'doNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].doNotVerifyRemoteGateways), createObject('value', true()))]", - "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'useRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].useRemoteGateways), createObject('value', false()))]" + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -3143,8 +3517,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3153,9 +3527,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -3164,7 +3538,7 @@ "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." } }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "type": "string", "metadata": { "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." @@ -3209,7 +3583,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -3218,7 +3592,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -3255,14 +3629,14 @@ "virtualNetwork_peering_remote": { "copy": { "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", - "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3270,17 +3644,29 @@ "mode": "Incremental", "parameters": { "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" }, - "name": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringName'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringName), createObject('value', format('{0}-{1}', last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')), parameters('name'))))]", - "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowForwardedTraffic), createObject('value', true()))]", - "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowGatewayTransit), createObject('value', false()))]", - "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowVirtualNetworkAccess), createObject('value', true()))]", - "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringDoNotVerifyRemoteGateways), createObject('value', true()))]", - "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringUseRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringUseRemoteGateways), createObject('value', false()))]" + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -3288,8 +3674,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -3298,9 +3684,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -3309,7 +3695,7 @@ "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." } }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "type": "string", "metadata": { "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." @@ -3354,7 +3740,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -3363,7 +3749,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -3426,8 +3812,8 @@ "description": "The names of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" } }, "subnetResourceIds": { @@ -3436,8 +3822,8 @@ "description": "The resource IDs of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('name'), parameters('subnets')[copyIndex()].name)]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" } }, "location": { @@ -3445,7 +3831,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetwork', '2023-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } @@ -3487,8 +3873,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "15855049387961116888" + "version": "0.30.23.60470", + "templateHash": "15250207882926040999" } }, "parameters": { @@ -13299,28 +13685,7 @@ "[parameters('virtualNetworkDeploymentScriptAddressPrefix')]" ] }, - "subnets": { - "value": [ - { - "addressPrefix": "[if(not(empty(parameters('resourceProviders'))), cidrSubnet(parameters('virtualNetworkDeploymentScriptAddressPrefix'), 24, 0), null())]", - "name": "ds-subnet-001", - "networkSecurityGroupResourceId": "[if(not(empty(parameters('resourceProviders'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('deploymentScriptResourceGroupName')), 'Microsoft.Resources/deployments', variables('deploymentNames').createDsNsg), '2022-09-01').outputs.resourceId.value, null())]", - "serviceEndpoints": [ - { - "service": "Microsoft.Storage" - } - ], - "delegations": [ - { - "name": "Microsoft.ContainerInstance.containerGroups", - "properties": { - "serviceName": "Microsoft.ContainerInstance/containerGroups" - } - } - ] - } - ] - }, + "subnets": "[if(not(empty(parameters('resourceProviders'))), createObject('value', createArray(createObject('addressPrefix', if(not(empty(parameters('resourceProviders'))), cidrSubnet(parameters('virtualNetworkDeploymentScriptAddressPrefix'), 24, 0), null()), 'name', 'ds-subnet-001', 'networkSecurityGroupResourceId', if(not(empty(parameters('resourceProviders'))), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('deploymentScriptResourceGroupName')), 'Microsoft.Resources/deployments', variables('deploymentNames').createDsNsg), '2022-09-01').outputs.resourceId.value, null()), 'serviceEndpoints', createArray('Microsoft.Storage'), 'delegation', 'Microsoft.ContainerInstance/containerGroups'))), createObject('value', null()))]", "enableTelemetry": { "value": "[parameters('enableTelemetry')]" } @@ -13332,8 +13697,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16637670595978489426" + "version": "0.29.47.4906", + "templateHash": "15949466154563447171" }, "name": "Virtual Networks", "description": "This module deploys a Virtual Network (vNet).", @@ -13370,6 +13735,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -13550,6 +13922,242 @@ } }, "nullable": true + }, + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + } } }, "parameters": { @@ -13572,32 +14180,48 @@ "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." } }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, "subnets": { "type": "array", - "defaultValue": [], + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, "metadata": { "description": "Optional. An Array of subnets to deploy to the Virtual Network." } }, "dnsServers": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { "description": "Optional. DNS Servers associated to the Virtual Network." } }, "ddosProtectionPlanResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." } }, "peerings": { "type": "array", - "defaultValue": [], + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, "metadata": { - "description": "Optional. Virtual Network Peerings configurations." + "description": "Optional. Virtual Network Peering configurations." } }, "vnetEncryption": { @@ -13657,15 +14281,29 @@ "metadata": { "description": "Optional. Enable/Disable usage telemetry for module." } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -13673,8 +14311,8 @@ "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.1.7', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -13692,42 +14330,21 @@ }, "virtualNetwork": { "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "properties": { - "copy": [ - { - "name": "subnets", - "count": "[length(parameters('subnets'))]", - "input": { - "name": "[parameters('subnets')[copyIndex('subnets')].name]", - "properties": { - "addressPrefix": "[parameters('subnets')[copyIndex('subnets')].addressPrefix]", - "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'addressPrefixes'), parameters('subnets')[copyIndex('subnets')].addressPrefixes, createArray())]", - "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'applicationGatewayIPConfigurations'), parameters('subnets')[copyIndex('subnets')].applicationGatewayIPConfigurations, createArray())]", - "delegations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'delegations'), parameters('subnets')[copyIndex('subnets')].delegations, createArray())]", - "ipAllocations": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'ipAllocations'), parameters('subnets')[copyIndex('subnets')].ipAllocations, createArray())]", - "natGateway": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].natGatewayResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", - "networkSecurityGroup": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'networkSecurityGroupResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].networkSecurityGroupResourceId), null())]", - "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateEndpointNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateEndpointNetworkPolicies, null())]", - "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'privateLinkServiceNetworkPolicies'), parameters('subnets')[copyIndex('subnets')].privateLinkServiceNetworkPolicies, null())]", - "routeTable": "[if(and(contains(parameters('subnets')[copyIndex('subnets')], 'routeTableResourceId'), not(empty(parameters('subnets')[copyIndex('subnets')].routeTableResourceId))), createObject('id', parameters('subnets')[copyIndex('subnets')].routeTableResourceId), null())]", - "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpoints'), parameters('subnets')[copyIndex('subnets')].serviceEndpoints, createArray())]", - "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex('subnets')], 'serviceEndpointPolicies'), parameters('subnets')[copyIndex('subnets')].serviceEndpointPolicies, createArray())]" - } - } - } - ], "addressSpace": { "addressPrefixes": "[parameters('addressPrefixes')]" }, + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]" + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" } }, "virtualNetwork_lock": { @@ -13788,20 +14405,20 @@ "virtualNetwork_roleAssignments": { "copy": { "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], 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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "virtualNetwork" @@ -13810,7 +14427,7 @@ "virtualNetwork_subnets": { "copy": { "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", "mode": "serial", "batchSize": 1 }, @@ -13827,23 +14444,50 @@ "value": "[parameters('name')]" }, "name": { - "value": "[parameters('subnets')[copyIndex()].name]" + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" }, "addressPrefix": { - "value": "[parameters('subnets')[copyIndex()].addressPrefix]" - }, - "addressPrefixes": "[if(contains(parameters('subnets')[copyIndex()], 'addressPrefixes'), createObject('value', parameters('subnets')[copyIndex()].addressPrefixes), createObject('value', createArray()))]", - "applicationGatewayIPConfigurations": "[if(contains(parameters('subnets')[copyIndex()], 'applicationGatewayIPConfigurations'), createObject('value', parameters('subnets')[copyIndex()].applicationGatewayIPConfigurations), createObject('value', createArray()))]", - "delegations": "[if(contains(parameters('subnets')[copyIndex()], 'delegations'), createObject('value', parameters('subnets')[copyIndex()].delegations), createObject('value', createArray()))]", - "ipAllocations": "[if(contains(parameters('subnets')[copyIndex()], 'ipAllocations'), createObject('value', parameters('subnets')[copyIndex()].ipAllocations), createObject('value', createArray()))]", - "natGatewayResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'natGatewayResourceId'), createObject('value', parameters('subnets')[copyIndex()].natGatewayResourceId), createObject('value', ''))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('subnets')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", - "privateEndpointNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateEndpointNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateEndpointNetworkPolicies), createObject('value', ''))]", - "privateLinkServiceNetworkPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'privateLinkServiceNetworkPolicies'), createObject('value', parameters('subnets')[copyIndex()].privateLinkServiceNetworkPolicies), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('subnets')[copyIndex()], 'roleAssignments'), createObject('value', parameters('subnets')[copyIndex()].roleAssignments), createObject('value', createArray()))]", - "routeTableResourceId": "[if(contains(parameters('subnets')[copyIndex()], 'routeTableResourceId'), createObject('value', parameters('subnets')[copyIndex()].routeTableResourceId), createObject('value', ''))]", - "serviceEndpointPolicies": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpointPolicies'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpointPolicies), createObject('value', createArray()))]", - "serviceEndpoints": "[if(contains(parameters('subnets')[copyIndex()], 'serviceEndpoints'), createObject('value', parameters('subnets')[copyIndex()].serviceEndpoints), createObject('value', createArray()))]" + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -13852,8 +14496,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "9634407864982934565" + "version": "0.29.47.4906", + "templateHash": "5699372618313647761" }, "name": "Virtual Network Subnets", "description": "This module deploys a Virtual Network Subnet.", @@ -13865,6 +14509,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -13931,7 +14582,7 @@ "name": { "type": "string", "metadata": { - "description": "Optional. The Name of the subnet resource." + "description": "Requird. The Name of the subnet resource." } }, "virtualNetworkName": { @@ -13942,41 +14593,45 @@ }, "addressPrefix": { "type": "string", + "nullable": true, "metadata": { - "description": "Required. The address prefix for the subnet." + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." } }, "networkSecurityGroupResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the network security group to assign to the subnet." } }, "routeTableResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the route table to assign to the subnet." } }, "serviceEndpoints": { "type": "array", + "items": { + "type": "string" + }, "defaultValue": [], "metadata": { "description": "Optional. The service endpoints to enable on the subnet." } }, - "delegations": { - "type": "array", - "defaultValue": [], + "delegation": { + "type": "string", + "nullable": true, "metadata": { - "description": "Optional. The delegations to enable on the subnet." + "description": "Optional. The delegation to enable on the subnet." } }, "natGatewayResourceId": { "type": "string", - "defaultValue": "", + "nullable": true, "metadata": { "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." } @@ -13990,7 +14645,7 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." } }, "privateLinkServiceNetworkPolicies": { @@ -14002,28 +14657,42 @@ "" ], "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." } }, "addressPrefixes": { "type": "array", - "defaultValue": [], + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. List of address prefixes for the subnet." + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." } }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." } }, - "ipAllocations": { + "applicationGatewayIPConfigurations": { "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. Array of IpAllocation which reference this subnet." + "description": "Optional. Application gateway IP configurations of virtual network resource." } }, "serviceEndpointPolicies": { @@ -14041,12 +14710,19 @@ } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "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')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -14054,26 +14730,35 @@ "virtualNetwork": { "existing": true, "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[parameters('virtualNetworkName')]" }, "subnet": { "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "serviceEndpoints": "[parameters('serviceEndpoints')]", - "delegations": "[parameters('delegations')]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", - "addressPrefixes": "[parameters('addressPrefixes')]", "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "ipAllocations": "[parameters('ipAllocations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" }, "dependsOn": [ "virtualNetwork" @@ -14082,20 +14767,20 @@ "subnet_roleAssignments": { "copy": { "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], 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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "subnet" @@ -14124,19 +14809,19 @@ }, "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" }, - "subnetAddressPrefix": { + "addressPrefix": { "type": "string", "metadata": { "description": "The address prefix for the subnet." }, - "value": "[reference('subnet').addressPrefix]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" }, - "subnetAddressPrefixes": { + "addressPrefixes": { "type": "array", "metadata": { "description": "List of address prefixes for the subnet." }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" } } } @@ -14148,7 +14833,7 @@ "virtualNetwork_peering_local": { "copy": { "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", @@ -14162,15 +14847,27 @@ "localVnetName": { "value": "[parameters('name')]" }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" }, - "name": "[if(contains(parameters('peerings')[copyIndex()], 'name'), createObject('value', parameters('peerings')[copyIndex()].name), createObject('value', format('{0}-{1}', parameters('name'), last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')))))]", - "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'allowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].allowForwardedTraffic), createObject('value', true()))]", - "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'allowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].allowGatewayTransit), createObject('value', false()))]", - "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'allowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].allowVirtualNetworkAccess), createObject('value', true()))]", - "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'doNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].doNotVerifyRemoteGateways), createObject('value', true()))]", - "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'useRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].useRemoteGateways), createObject('value', false()))]" + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -14178,8 +14875,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -14188,9 +14885,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -14199,7 +14896,7 @@ "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." } }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "type": "string", "metadata": { "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." @@ -14244,7 +14941,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -14253,7 +14950,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -14290,14 +14987,14 @@ "virtualNetwork_peering_remote": { "copy": { "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" + "count": "[length(coalesce(parameters('peerings'), createArray()))]" }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), false())]", + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[2]]", - "resourceGroup": "[split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')[4]]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -14305,17 +15002,29 @@ "mode": "Incremental", "parameters": { "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" }, - "name": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringName'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringName), createObject('value', format('{0}-{1}', last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/')), parameters('name'))))]", - "allowForwardedTraffic": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowForwardedTraffic'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowForwardedTraffic), createObject('value', true()))]", - "allowGatewayTransit": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowGatewayTransit'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowGatewayTransit), createObject('value', false()))]", - "allowVirtualNetworkAccess": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringAllowVirtualNetworkAccess), createObject('value', true()))]", - "doNotVerifyRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringDoNotVerifyRemoteGateways), createObject('value', true()))]", - "useRemoteGateways": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringUseRemoteGateways'), createObject('value', parameters('peerings')[copyIndex()].remotePeeringUseRemoteGateways), createObject('value', false()))]" + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -14323,8 +15032,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "39994426069187924" + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" }, "name": "Virtual Network Peerings", "description": "This module deploys a Virtual Network Peering.", @@ -14333,9 +15042,9 @@ "parameters": { "name": { "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", "metadata": { - "description": "Optional. The Name of Vnet Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." } }, "localVnetName": { @@ -14344,7 +15053,7 @@ "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." } }, - "remoteVirtualNetworkId": { + "remoteVirtualNetworkResourceId": { "type": "string", "metadata": { "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." @@ -14389,7 +15098,7 @@ "resources": [ { "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2023-11-01", + "apiVersion": "2024-01-01", "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", "properties": { "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", @@ -14398,7 +15107,7 @@ "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", "useRemoteGateways": "[parameters('useRemoteGateways')]", "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "id": "[parameters('remoteVirtualNetworkResourceId')]" } } } @@ -14461,8 +15170,8 @@ "description": "The names of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" } }, "subnetResourceIds": { @@ -14471,8 +15180,8 @@ "description": "The resource IDs of the deployed subnets." }, "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('name'), parameters('subnets')[copyIndex()].name)]" + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" } }, "location": { @@ -14480,7 +15189,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('virtualNetwork', '2023-11-01', 'full').location]" + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" } } } diff --git a/avm/ptn/lz/sub-vending/modules/readTagsResourceGroup.bicep b/avm/ptn/lz/sub-vending/modules/readTagsResourceGroup.bicep index 0f3301f974..b633ed6575 100644 --- a/avm/ptn/lz/sub-vending/modules/readTagsResourceGroup.bicep +++ b/avm/ptn/lz/sub-vending/modules/readTagsResourceGroup.bicep @@ -6,4 +6,4 @@ resource tags 'Microsoft.Resources/tags@2019-10-01' existing = { } @description('Tags currently applied to the subscription level') -output existingTags object = contains(tags.properties, 'tags') ? tags.properties.tags : {} +output existingTags object = tags.properties.?tags ?? {} diff --git a/avm/ptn/lz/sub-vending/modules/readTagsSubscription.bicep b/avm/ptn/lz/sub-vending/modules/readTagsSubscription.bicep index 65b2457259..6c9f04feef 100644 --- a/avm/ptn/lz/sub-vending/modules/readTagsSubscription.bicep +++ b/avm/ptn/lz/sub-vending/modules/readTagsSubscription.bicep @@ -8,4 +8,4 @@ resource tags 'Microsoft.Resources/tags@2019-10-01' existing = { } @description('Tags currently applied to the subscription level') -output existingTags object = contains(tags.properties, 'tags') ? tags.properties.tags : {} +output existingTags object = tags.properties.?tags ?? {} diff --git a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep index 6a6e2e6195..d0b80795eb 100644 --- a/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep +++ b/avm/ptn/lz/sub-vending/modules/subResourceWrapper.bicep @@ -188,11 +188,18 @@ param deploymentScriptManagedIdentityName string @sys.description('The name of the storage account for the deployment script.') param deploymentScriptStorageAccountName string +@sys.description('Optional. The number of blank ARM deployments to create sequentially to introduce a delay to the Subscription being moved to the target Management Group being, if set, to allow for background platform RBAC inheritance to occur.') +param managementGroupAssociationDelayCount int = 15 + // VARIABLES // Deployment name variables // LIMITS: Tenant = 64, Management Group = 64, Subscription = 64, Resource Group = 64 var deploymentNames = { + moveSubscriptionToManagementGroupDelay: take( + 'lz-vend-move-sub-delay-${uniqueString(subscriptionId, subscriptionManagementGroupId, deployment().name)}', + 64 + ) moveSubscriptionToManagementGroup: take( 'lz-vend-move-sub-${uniqueString(subscriptionId, subscriptionManagementGroupId, deployment().name)}', 64 @@ -295,7 +302,7 @@ var virtualWanHubSubscriptionId = (!empty(virtualHubResourceIdChecked) ? split(v var virtualWanHubResourceGroupName = (!empty(virtualHubResourceIdChecked) ? split(virtualHubResourceIdChecked, '/')[4] : '') -var virtualWanHubConnectionName = 'vhc-${guid(virtualHubResourceIdChecked, virtualNetworkName, virtualNetworkResourceGroupName, virtualNetworkLocation, subscriptionId)}' +var virtualWanHubConnectionName = 'vhc-${virtualNetworkName}-${substring(guid(virtualHubResourceIdChecked, virtualNetworkName, virtualNetworkResourceGroupName, virtualNetworkLocation, subscriptionId), 0, 5)}' var virtualWanHubConnectionAssociatedRouteTable = !empty(virtualNetworkVwanAssociatedRouteTableResourceId) ? virtualNetworkVwanAssociatedRouteTableResourceId : '${virtualHubResourceIdChecked}/hubRouteTables/defaultRouteTable' @@ -313,8 +320,28 @@ var resourceProvidersFormatted = replace(string(resourceProviders), '"', '\\"') // RESOURCES & MODULES +@batchSize(1) +#disable-next-line no-deployments-resources +resource moveSubscriptionToManagementGroupDelay 'Microsoft.Resources/deployments@2024-03-01' = [ + for (cycle, i) in range(0, managementGroupAssociationDelayCount): if (subscriptionManagementGroupAssociationEnabled && !empty(subscriptionManagementGroupId)) { + name: '${deploymentNames.moveSubscriptionToManagementGroupDelay}-${i}' + location: virtualNetworkLocation + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } + } +] + module moveSubscriptionToManagementGroup './managementGroupSubscription.bicep' = if (subscriptionManagementGroupAssociationEnabled && !empty(subscriptionManagementGroupId)) { scope: managementGroup(subscriptionManagementGroupId) + dependsOn: [ + moveSubscriptionToManagementGroupDelay + ] name: deploymentNames.moveSubscriptionToManagementGroup params: { subscriptionManagementGroupId: subscriptionManagementGroupId @@ -361,7 +388,7 @@ module tagResourceGroup 'tags.bicep' = if (virtualNetworkEnabled && !empty(virtu } } -module createLzVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (virtualNetworkEnabled && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) { +module createLzVnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (virtualNetworkEnabled && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) { dependsOn: [ createResourceGroupForLzNetworking ] @@ -377,19 +404,19 @@ module createLzVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (virt peerings: (virtualNetworkEnabled && virtualNetworkPeeringEnabled && !empty(hubVirtualNetworkResourceIdChecked) && !empty(virtualNetworkName) && !empty(virtualNetworkAddressSpace) && !empty(virtualNetworkLocation) && !empty(virtualNetworkResourceGroupName)) ? [ { + remoteVirtualNetworkResourceId: hubVirtualNetworkResourceIdChecked allowForwardedTraffic: true allowVirtualNetworkAccess: true allowGatewayTransit: false useRemoteGateways: virtualNetworkUseRemoteGateways remotePeeringEnabled: virtualNetworkPeeringEnabled - remoteVirtualNetworkId: hubVirtualNetworkResourceIdChecked remotePeeringAllowForwardedTraffic: true remotePeeringAllowVirtualNetworkAccess: true remotePeeringAllowGatewayTransit: true remotePeeringUseRemoteGateways: false } ] - : [] + : null enableTelemetry: enableTelemetry } } @@ -552,7 +579,7 @@ module createDsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' } } -module createDsVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (!empty(resourceProviders)) { +module createDsVnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (!empty(resourceProviders)) { scope: resourceGroup(subscriptionId, deploymentScriptResourceGroupName) name: deploymentNames.createdsVnet params: { @@ -561,26 +588,21 @@ module createDsVnet 'br/public:avm/res/network/virtual-network:0.1.7' = if (!emp addressPrefixes: [ virtualNetworkDeploymentScriptAddressPrefix ] - subnets: [ - { - addressPrefix: !empty(resourceProviders) ? cidrSubnet(virtualNetworkDeploymentScriptAddressPrefix, 24, 0) : null - name: 'ds-subnet-001' - networkSecurityGroupResourceId: !empty(resourceProviders) ? createDsNsg.outputs.resourceId : null - serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - ] - delegations: [ + subnets: !empty(resourceProviders) + ? [ { - name: 'Microsoft.ContainerInstance.containerGroups' - properties: { - serviceName: 'Microsoft.ContainerInstance/containerGroups' - } + addressPrefix: !empty(resourceProviders) + ? cidrSubnet(virtualNetworkDeploymentScriptAddressPrefix, 24, 0) + : null + name: 'ds-subnet-001' + networkSecurityGroupResourceId: !empty(resourceProviders) ? createDsNsg.outputs.resourceId : null + serviceEndpoints: [ + 'Microsoft.Storage' + ] + delegation: 'Microsoft.ContainerInstance/containerGroups' } ] - } - ] + : null enableTelemetry: enableTelemetry } } diff --git a/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 b/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 index 3bbc201cf5..57396617c6 100644 --- a/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 +++ b/avm/ptn/lz/sub-vending/scripts/Register-SubscriptionResourceProviderList.ps1 @@ -1,6 +1,6 @@ Param( -[string]$subscriptionId, -[string]$resourceProviders + [string]$subscriptionId, + [string]$resourceProviders ) $ErrorActionPreference = 'SilentlyContinue' @@ -18,81 +18,81 @@ $DeploymentScriptOutputs = @{} ############################################## if ($providers.Count -gt 0) { - foreach ($provider in $providers.keys) { - try { - # Registering resource providers - $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState - # Check if the providered is registered - if ($providerStatus -eq 'NotRegistered') { - Write-Output "`n Registering the '$provider' provider" - if (Register-AzResourceProvider -ProviderNamespace $provider) { - Write-Output "`n The registration for provider'$provider' has started successfully" - } else { - Write-Output "`n The '$provider' provider has not been registered successfully" - $failedProviders += ",$provider" - } - } elseif ($providerStatus -eq 'Registering') { - Write-Output "`n The '$provider' provider is in registering state" - $failedProviders += ",$provider" - } elseif ( $null -eq $providerStatus) { - Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" - $failedProviders += ",$provider" - } - - if ($failedProviders.length -gt 0) { - $output = $failedProviders.substring(1) - } else { - $output = 'No failures' - } - $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output - } catch { - Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" - $failedProviders += ",$provider" - if ($failedProviders.length -gt 0) { - $output = $failedProviders.substring(1) - } - $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output - } - # Registering resource providers features - $features = $providers[$provider] - if ($features.length -gt 0) { - foreach ($feature in $features) { + foreach ($provider in $providers.keys) { try { - # Define variables - $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState - # Check if the feature is registered - if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') { - Write-Output "`n Registering the '$feature' feature" - if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) { - Write-Output "`n The The registration for feature '$feature' has started successfully" + # Registering resource providers + $providerStatus = (Get-AzResourceProvider -ListAvailable | Where-Object ProviderNamespace -EQ $provider).registrationState + # Check if the providered is registered + if ($providerStatus -eq 'NotRegistered') { + Write-Output "`n Registering the '$provider' provider" + if (Register-AzResourceProvider -ProviderNamespace $provider) { + Write-Output "`n The registration for provider'$provider' has started successfully" + } else { + Write-Output "`n The '$provider' provider has not been registered successfully" + $failedProviders += ",$provider" + } + } elseif ($providerStatus -eq 'Registering') { + Write-Output "`n The '$provider' provider is in registering state" + $failedProviders += ",$provider" + } elseif ( $null -eq $providerStatus) { + Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" + $failedProviders += ",$provider" + } + + if ($failedProviders.length -gt 0) { + $output = $failedProviders.substring(1) } else { - Write-Output "`n The '$feature' feature has not been registered successfully" - $failedFeatures += ",$feature" + $output = 'No failures' } - } elseif ($null -eq $featureStatus) { - Write-Output "`n The '$feature' feature doesn't exist." - $failedFeatures += ",$feature" - } - if ($failedFeatures.length -gt 0) { - $output = $failedFeatures.substring(1) - } else { - $output = 'No failures' - } - $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output } catch { - Write-Output "`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid" - $failedFeatures += ",$feature" - if ($failedFeatures.length -gt 0) { - $output = $failedFeatures.substring(1) - } - $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + Write-Output "`n There was a problem registering the '$provider' provider. Please make sure this provider namespace is valid" + $failedProviders += ",$provider" + if ($failedProviders.length -gt 0) { + $output = $failedProviders.substring(1) + } + $DeploymentScriptOutputs['failedProvidersRegistrations'] = $output + } + # Registering resource providers features + $features = $providers[$provider] + if ($features.length -gt 0) { + foreach ($feature in $features) { + try { + # Define variables + $featureStatus = (Get-AzProviderFeature -ListAvailable | Where-Object FeatureName -EQ $feature).RegistrationState + # Check if the feature is registered + if ($featureStatus -eq 'NotRegistered' -or $featureStatus -eq 'Unregistered') { + Write-Output "`n Registering the '$feature' feature" + if (Register-AzProviderFeature -FeatureName $feature -ProviderNamespace $provider) { + Write-Output "`n The The registration for feature '$feature' has started successfully" + } else { + Write-Output "`n The '$feature' feature has not been registered successfully" + $failedFeatures += ",$feature" + } + } elseif ($null -eq $featureStatus) { + Write-Output "`n The '$feature' feature doesn't exist." + $failedFeatures += ",$feature" + } + if ($failedFeatures.length -gt 0) { + $output = $failedFeatures.substring(1) + } else { + $output = 'No failures' + } + $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + } catch { + Write-Output "`n There was a problem registering the '$feature' feature. Please make sure this feature name is valid" + $failedFeatures += ",$feature" + if ($failedFeatures.length -gt 0) { + $output = $failedFeatures.substring(1) + } + $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output + } + } + } else { + $output = 'No failures' + $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output } - } - } else { - $output = 'No failures' - $DeploymentScriptOutputs['failedFeaturesRegistrations'] = $output } - } } else { - Write-Output "`n No providers or features to register" + Write-Output "`n No providers or features to register" } diff --git a/avm/ptn/network/hub-networking/README.md b/avm/ptn/network/hub-networking/README.md new file mode 100644 index 0000000000..490e420691 --- /dev/null +++ b/avm/ptn/network/hub-networking/README.md @@ -0,0 +1,2213 @@ +# Hub Networking `[Network/HubNetworking]` + +This module is designed to simplify the creation of multi-region hub networks in Azure. It will create a number of virtual networks and subnets, and optionally peer them together in a mesh topology with routing. + +## 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.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/azureFirewalls` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/azureFirewalls) | +| `Microsoft.Network/bastionHosts` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-11-01/bastionHosts) | +| `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | +| `Microsoft.Network/routeTables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/routeTables) | +| `Microsoft.Network/routeTables/routes` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/routeTables/routes) | +| `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/subnets` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | + +## 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/ptn/network/hub-networking:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [No Addons](#example-3-no-addons) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = { + name: 'hubNetworkingDeployment' + params: { + location: '' + } +} +``` + +
    +

    + +

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

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param location = '' +``` + +
    +

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

    + +via Bicep module + +```bicep +module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = { + name: 'hubNetworkingDeployment' + params: { + hubVirtualNetworks: { + hub1: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub1-waf-pip' + } + threatIntelMode: 'Alert' + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remoteVirtualNetworkName: 'hub2' + useRemoteGateways: false + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + hub2: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub2-waf-pip' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: false + flowTimeoutInMinutes: 10 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub2Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remoteVirtualNetworkName: 'hub1' + useRemoteGateways: false + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "hubVirtualNetworks": { + "value": { + "hub1": { + "addressPrefixes": "", + "azureFirewallSettings": { + "azureSkuTier": "Standard", + "enableTelemetry": true, + "location": "", + "publicIPAddressObject": { + "name": "hub1-waf-pip" + }, + "threatIntelMode": "Alert" + }, + "bastionHost": { + "disableCopyPaste": true, + "enableFileCopy": false, + "enableIpConnect": false, + "enableShareableLink": false, + "scaleUnits": 2, + "skuName": "Standard" + }, + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "dnsServers": [ + "10.0.1.4", + "10.0.1.5" + ], + "enableAzureFirewall": true, + "enableBastion": true, + "enablePeering": false, + "enableTelemetry": true, + "flowTimeoutInMinutes": 30, + "location": "", + "lock": { + "kind": "CanNotDelete", + "name": "hub1Lock" + }, + "peeringSettings": [ + { + "allowForwardedTraffic": true, + "allowGatewayTransit": false, + "allowVirtualNetworkAccess": true, + "remoteVirtualNetworkName": "hub2", + "useRemoteGateways": false + } + ], + "routes": [ + { + "name": "defaultRoute", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopType": "Internet" + } + } + ], + "subnets": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "vnetEncryption": false, + "vnetEncryptionEnforcement": "AllowUnencrypted" + }, + "hub2": { + "addressPrefixes": "", + "azureFirewallSettings": { + "azureSkuTier": "Standard", + "enableTelemetry": true, + "location": "", + "publicIPAddressObject": { + "name": "hub2-waf-pip" + }, + "threatIntelMode": "Alert", + "zones": [ + 1, + 2, + 3 + ] + }, + "bastionHost": { + "disableCopyPaste": true, + "enableFileCopy": false, + "enableIpConnect": false, + "enableShareableLink": false, + "scaleUnits": 2, + "skuName": "Standard" + }, + "enableAzureFirewall": true, + "enableBastion": true, + "enablePeering": false, + "enableTelemetry": false, + "flowTimeoutInMinutes": 10, + "location": "", + "lock": { + "kind": "CanNotDelete", + "name": "hub2Lock" + }, + "peeringSettings": [ + { + "allowForwardedTraffic": true, + "allowGatewayTransit": false, + "allowVirtualNetworkAccess": true, + "remoteVirtualNetworkName": "hub1", + "useRemoteGateways": false + } + ], + "routes": [ + { + "name": "defaultRoute", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopType": "Internet" + } + } + ], + "subnets": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "vnetEncryption": false, + "vnetEncryptionEnforcement": "AllowUnencrypted" + } + } + }, + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param hubVirtualNetworks = { + hub1: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub1-waf-pip' + } + threatIntelMode: 'Alert' + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.4' + '10.0.1.5' + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remoteVirtualNetworkName: 'hub2' + useRemoteGateways: false + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + hub2: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub2-waf-pip' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: false + flowTimeoutInMinutes: 10 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub2Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remoteVirtualNetworkName: 'hub1' + useRemoteGateways: false + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } +} +param location = '' +``` + +
    +

    + +### Example 3: _No Addons_ + +This instance deploys the module with no add-ons (Firewall / Bastion) enabled. + + +

    + +via Bicep module + +```bicep +module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = { + name: 'hubNetworkingDeployment' + params: { + hubVirtualNetworks: { + hub1: { + addressPrefixes: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: false + enableBastion: false + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "hubVirtualNetworks": { + "value": { + "hub1": { + "addressPrefixes": "", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "dnsServers": [ + "10.0.1.6", + "10.0.1.7" + ], + "enableAzureFirewall": false, + "enableBastion": false, + "enablePeering": false, + "enableTelemetry": true, + "flowTimeoutInMinutes": 30, + "location": "", + "lock": { + "kind": "CanNotDelete", + "name": "hub1Lock" + }, + "routes": [ + { + "name": "defaultRoute", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopType": "Internet" + } + } + ], + "subnets": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "vnetEncryption": false, + "vnetEncryptionEnforcement": "AllowUnencrypted" + } + } + }, + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param hubVirtualNetworks = { + hub1: { + addressPrefixes: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: false + enableBastion: false + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } +} +param location = '' +``` + +
    +

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

    + +via Bicep module + +```bicep +module hubNetworking 'br/public:avm/ptn/network/hub-networking:' = { + name: 'hubNetworkingDeployment' + params: { + hubVirtualNetworks: { + hub1: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub1PublicIp' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "hubVirtualNetworks": { + "value": { + "hub1": { + "addressPrefixes": "", + "azureFirewallSettings": { + "azureSkuTier": "Standard", + "enableTelemetry": true, + "location": "", + "publicIPAddressObject": { + "name": "hub1PublicIp" + }, + "threatIntelMode": "Alert", + "zones": [ + 1, + 2, + 3 + ] + }, + "bastionHost": { + "disableCopyPaste": true, + "enableFileCopy": false, + "enableIpConnect": false, + "enableShareableLink": false, + "scaleUnits": 2, + "skuName": "Standard" + }, + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "dnsServers": [ + "10.0.1.6", + "10.0.1.7" + ], + "enableAzureFirewall": true, + "enableBastion": true, + "enablePeering": false, + "enableTelemetry": true, + "flowTimeoutInMinutes": 30, + "location": "", + "lock": { + "kind": "CanNotDelete", + "name": "hub1Lock" + }, + "routes": [ + { + "name": "defaultRoute", + "properties": { + "addressPrefix": "0.0.0.0/0", + "nextHopType": "Internet" + } + } + ], + "subnets": [ + { + "addressPrefix": "", + "name": "GatewaySubnet" + }, + { + "addressPrefix": "", + "name": "AzureFirewallSubnet" + }, + { + "addressPrefix": "", + "name": "AzureBastionSubnet" + } + ], + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + }, + "vnetEncryption": false, + "vnetEncryptionEnforcement": "AllowUnencrypted" + } + } + }, + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/hub-networking:' + +param hubVirtualNetworks = { + hub1: { + addressPrefixes: '' + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: '' + publicIPAddressObject: { + name: 'hub1PublicIp' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + dnsServers: [ + '10.0.1.6' + '10.0.1.7' + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: '' + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } +} +param location = '' +``` + +
    +

    + +## Parameters + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`hubVirtualNetworks`](#parameter-hubvirtualnetworks) | object | A map of the hub virtual networks to create. | +| [`location`](#parameter-location) | string | Location for all Resources. | + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `hubVirtualNetworks` + +A map of the hub virtual networks to create. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`>Any_other_property<`](#parameter-hubvirtualnetworks>any_other_property<) | object | The hub virtual networks to create. | + +### Parameter: `hubVirtualNetworks.>Any_other_property<` + +The hub virtual networks to create. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`addressPrefixes`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.addressPrefixes` + +The address prefixes for the virtual network. + +- Required: Yes +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings` + +The Azure Firewall config. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`additionalPublicIpConfigurations`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.azureFirewallSettings.additionalPublicIpConfigurations` + +Additional public IP configurations. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.applicationRuleCollections` + +Application rule collections. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.azureSkuTier` + +Azure Firewall SKU. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings` + +Diagnostic settings. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.azureFirewallSettings.diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyAny_other_property<.azureFirewallSettings.diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyAny_other_property<.azureFirewallSettings.diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.firewallPolicyId` + +Firewall policy ID. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.hubIpAddresses` + +Hub IP addresses. + +- Required: No +- Type: object + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.location` + +The location of the virtual network. Defaults to the location of the resource group. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.lock` + +Lock settings. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyAny_other_property<.azureFirewallSettings.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.managementIPAddressObject` + +Management IP address configuration. + +- Required: No +- Type: object + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.managementIPResourceID` + +Management IP resource ID. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.natRuleCollections` + +NAT rule collections. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.networkRuleCollections` + +Network rule collections. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.publicIPAddressObject` + +Public IP address object. + +- Required: No +- Type: object + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.publicIPResourceID` + +Public IP resource ID. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.roleAssignments` + +Role assignments. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.azureFirewallSettings.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.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: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.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: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.threatIntelMode` + +Threat Intel mode. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.virtualHub` + +Virtual Hub ID. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.azureFirewallSettings.zones` + +Zones. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.bastionHost` + +The Azure Bastion config. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`disableCopyPaste`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.bastionHost.disableCopyPaste` + +Enable/Disable copy/paste functionality. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.bastionHost.enableFileCopy` + +Enable/Disable file copy functionality. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.bastionHost.enableIpConnect` + +Enable/Disable IP connect functionality. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.bastionHost.enableShareableLink` + +Enable/Disable shareable link functionality. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.bastionHost.scaleUnits` + +The number of scale units for the Bastion host. Defaults to 4. + +- Required: No +- Type: int + +### Parameter: `hubVirtualNetworks.>Any_other_property<.bastionHost.skuName` + +The SKU name of the Bastion host. Defaults to Standard. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.ddosProtectionPlanResourceId` + +The DDoS protection plan resource ID. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings` + +The diagnostic settings of the virtual network. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyAny_other_property<.diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyAny_other_property<.diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.dnsServers` + +The DNS servers of the virtual network. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.enableAzureFirewall` + +Enable/Disable Azure Firewall for the virtual network. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.enableBastion` + +Enable/Disable Azure Bastion for the virtual network. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.enablePeering` + +Enable/Disable peering for the virtual network. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.flowTimeoutInMinutes` + +The flow timeout in minutes. + +- Required: No +- Type: int + +### Parameter: `hubVirtualNetworks.>Any_other_property<.location` + +The location of the virtual network. Defaults to the location of the resource group. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.lock` + +The lock settings of the virtual network. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyAny_other_property<.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.peeringSettings` + +The peerings of the virtual network. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowForwardedTraffic`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.peeringSettings.allowForwardedTraffic` + +Allow forwarded traffic. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.peeringSettings.allowGatewayTransit` + +Allow gateway transit. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.peeringSettings.allowVirtualNetworkAccess` + +Allow virtual network access. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.peeringSettings.remoteVirtualNetworkName` + +Remote virtual network name. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.peeringSettings.useRemoteGateways` + +Use remote gateways. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.roleAssignments` + +The role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-hubvirtualnetworks>any_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyany_other_propertyAny_other_property<.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.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: `hubVirtualNetworks.>Any_other_property<.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: `hubVirtualNetworks.>Any_other_property<.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `hubVirtualNetworks.>Any_other_property<.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `hubVirtualNetworks.>Any_other_property<.routes` + +Routes to add to the virtual network route table. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.subnets` + +The subnets of the virtual network. + +- Required: No +- Type: array + +### Parameter: `hubVirtualNetworks.>Any_other_property<.tags` + +The tags of the virtual network. + +- Required: No +- Type: object + +### Parameter: `hubVirtualNetworks.>Any_other_property<.vnetEncryption` + +Enable/Disable VNet encryption. + +- Required: No +- Type: bool + +### Parameter: `hubVirtualNetworks.>Any_other_property<.vnetEncryptionEnforcement` + +The VNet encryption enforcement settings of the virtual network. + +- Required: No +- Type: string + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `hubAzureFirewalls` | array | Array of hub Azure Firewall resources. | +| `hubBastions` | array | Array of hub bastion resources. | +| `hubVirtualNetworks` | array | Array of hub virtual network resources. | +| `hubVirtualNetworkSubnets` | array | The subnets of the hub virtual network. | +| `resourceGroupName` | string | The resource group the resources were deployed into. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/azure-firewall:0.5.0` | Remote reference | +| `br/public:avm/res/network/bastion-host:0.4.0` | Remote reference | +| `br/public:avm/res/network/route-table:0.4.0` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | + +## 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/ptn/network/hub-networking/main.bicep b/avm/ptn/network/hub-networking/main.bicep new file mode 100644 index 0000000000..2f222c6bc0 --- /dev/null +++ b/avm/ptn/network/hub-networking/main.bicep @@ -0,0 +1,523 @@ +metadata name = 'Hub Networking' +metadata description = 'This module is designed to simplify the creation of multi-region hub networks in Azure. It will create a number of virtual networks and subnets, and optionally peer them together in a mesh topology with routing.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// +// Add your parameters here +// + +@description('Optional. A map of the hub virtual networks to create.') +param hubVirtualNetworks hubVirtualNetworkType + +// +// Add your variables here +var hubVirtualNetworkPeerings = [for (hub, index) in items(hubVirtualNetworks ?? {}): hub.value.?peeringSettings ?? []] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.network-hubnetworking.${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' + } + } + } + } +} + +// Create hub virtual networks +module hubVirtualNetwork 'br/public:avm/res/network/virtual-network:0.4.0' = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): { + name: '${uniqueString(deployment().name, location)}-${hub.key}-nvn' + params: { + // Required parameters + name: hub.key + addressPrefixes: hub.value.addressPrefixes + // Non-required parameters + ddosProtectionPlanResourceId: hub.value.?ddosProtectionPlanResourceId ?? '' + diagnosticSettings: hub.value.?diagnosticSettings ?? [] + dnsServers: hub.value.?dnsServers ?? [] + enableTelemetry: hub.value.?enableTelemetry ?? true + flowTimeoutInMinutes: hub.value.?flowTimeoutInMinutes ?? 0 + location: hub.value.?location ?? '' + lock: hub.value.?lock ?? {} + roleAssignments: hub.value.?roleAssignments ?? [] + subnets: hub.value.?subnets ?? [] + tags: hub.value.?tags ?? {} + vnetEncryption: hub.value.?vnetEncryption ?? false + vnetEncryptionEnforcement: hub.value.?vnetEncryptionEnforcement ?? '' + } + } +] + +// Create hub virtual network peerings +module hubVirtualNetworkPeer_remote 'modules/vnets.bicep' = [ + for (peer, index) in flatten(hubVirtualNetworkPeerings): { + name: '${uniqueString(deployment().name, location)}-${peer.remoteVirtualNetworkName}-nvnp' + params: { + name: peer.remoteVirtualNetworkName + } + dependsOn: hubVirtualNetwork + } +] + +// Create hub virtual network peerings +// resource hubVirtualNetworkPeer_remote 'Microsoft.Network/virtualNetworks@2023-11-01' existing = [ +// for (peer, index) in flatten(hubVirtualNetworkPeerings): { +// name: peer.remoteVirtualNetworkName +// } +// ] + +resource hubVirtualNetworkPeer_local 'Microsoft.Network/virtualNetworks@2024-01-01' existing = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): if (hub.value.enablePeering) { + name: hub.key + } +] + +resource hubVirtualNetworkPeering 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2024-01-01' = [ + for (peer, index) in (flatten(hubVirtualNetworkPeerings) ?? []): { + name: '${hubVirtualNetworkPeer_local[index].name}/${hubVirtualNetworkPeer_local[index].name}-to-${peer.remoteVirtualNetworkName}-peering' + properties: { + allowForwardedTraffic: peer.allowForwardedTraffic ?? false + allowGatewayTransit: peer.allowGatewayTransit ?? false + allowVirtualNetworkAccess: peer.allowVirtualNetworkAccess ?? true + useRemoteGateways: peer.useRemoteGateways ?? false + remoteVirtualNetwork: { + id: hubVirtualNetworkPeer_remote[index].outputs.resourceId + } + } + dependsOn: hubVirtualNetwork + } +] + +// Create hub virtual network route tables +module hubRouteTable 'br/public:avm/res/network/route-table:0.4.0' = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): { + name: '${uniqueString(deployment().name, location)}-${hub.key}-nrt' + params: { + name: hub.key + location: hub.value.?location ?? location + disableBgpRoutePropagation: true + enableTelemetry: hub.value.?enableTelemetry ?? true + roleAssignments: hub.value.?roleAssignments ?? [] + routes: hub.value.?routes ?? [] + tags: hub.value.?tags ?? {} + } + dependsOn: hubVirtualNetwork + } +] + +// Create hub virtual network route table route +resource hubRoute 'Microsoft.Network/routeTables/routes@2024-01-01' = [ + for (peer, index) in (flatten(hubVirtualNetworkPeerings) ?? []): { + name: '${hubVirtualNetworkPeer_local[index].name}/${hubVirtualNetworkPeer_local[index].name}-to-${peer.remoteVirtualNetworkName}-route' + properties: { + addressPrefix: hubVirtualNetworkPeer_remote[index].outputs.addressPrefix + nextHopType: 'VirtualAppliance' + nextHopIpAddress: hubAzureFirewall[index].outputs.privateIp + } + dependsOn: hubVirtualNetworkPeering + } +] + +// Create Bastion host if enabled +// AzureBastionSubnet is required to deploy Bastion service. This subnet must exist in the parsubnets array if you enable Bastion Service. +// There is a minimum subnet requirement of /27 prefix. +module hubBastion 'br/public:avm/res/network/bastion-host:0.4.0' = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): if (hub.value.enableBastion) { + name: '${uniqueString(deployment().name, location)}-${hub.key}-nbh' + params: { + // Required parameters + name: hub.key + virtualNetworkResourceId: hubVirtualNetwork[index].outputs.resourceId + // Non-required parameters + diagnosticSettings: hub.value.?diagnosticSettings ?? [] + disableCopyPaste: hub.value.?bastionHost.?disableCopyPaste ?? true + enableFileCopy: hub.value.?bastionHost.?enableFileCopy ?? false + enableIpConnect: hub.value.?bastionHost.?enableIpConnect ?? false + enableShareableLink: hub.value.?bastionHost.?enableShareableLink ?? false + location: hub.value.?location ?? location + enableTelemetry: hub.value.?enableTelemetry ?? true + roleAssignments: hub.value.?roleAssignments ?? [] + scaleUnits: hub.value.?bastionHost.?scaleUnits ?? 4 + skuName: hub.value.?bastionHost.?skuName ?? 'Standard' + tags: hub.value.?tags ?? {} + } + dependsOn: hubVirtualNetwork + } +] + +// Create Azure Firewall if enabled +// AzureFirewallSubnet is required to deploy Azure Firewall service. This subnet must exist in the subnets array if you enable Azure Firewall. +module hubAzureFirewall 'br/public:avm/res/network/azure-firewall:0.5.0' = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): if (hub.value.enableAzureFirewall) { + name: '${uniqueString(deployment().name, location)}-${hub.key}-naf' + params: { + // Required parameters + name: hub.key + // Conditional parameters + hubIPAddresses: hub.value.?azureFirewallSettings.?hubIpAddresses ?? {} + virtualHubId: hub.value.?azureFirewallSettings.?virtualHub ?? '' + virtualNetworkResourceId: hubVirtualNetwork[index].outputs.resourceId ?? '' + // Non-required parameters + additionalPublicIpConfigurations: hub.value.?azureFirewallSettings.?additionalPublicIpConfigurations ?? [] + applicationRuleCollections: hub.value.?azureFirewallSettings.?applicationRuleCollections ?? [] + azureSkuTier: hub.value.?azureFirewallSettings.?azureSkuTier ?? {} + diagnosticSettings: hub.value.?diagnosticSettings ?? [] + enableTelemetry: hub.value.?enableTelemetry ?? true + firewallPolicyId: hub.value.?azureFirewallSettings.?firewallPolicyId ?? '' + location: hub.value.?location ?? location + lock: hub.value.?lock ?? {} + managementIPAddressObject: hub.value.?azureFirewallSettings.?managementIPAddressObject ?? {} + managementIPResourceID: hub.value.?azureFirewallSettings.?managementIPResourceID ?? '' + natRuleCollections: hub.value.?azureFirewallSettings.?natRuleCollections ?? [] + networkRuleCollections: hub.value.?azureFirewallSettings.?networkRuleCollections ?? [] + publicIPAddressObject: hub.value.?azureFirewallSettings.?publicIPAddressObject ?? {} + publicIPResourceID: hub.value.?azureFirewallSettings.?publicIPResourceID ?? '' + roleAssignments: hub.value.?roleAssignments ?? [] + tags: hub.value.?tags ?? {} + threatIntelMode: hub.value.?azureFirewallSettings.?threatIntelMode ?? '' + zones: hub.value.?azureFirewallSettings.?zones ?? [] + } + dependsOn: hubVirtualNetwork + } +] + +module hubAzureFirewallSubnet 'modules/getSubnet.bicep' = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): if (hub.value.enableAzureFirewall) { + name: '${uniqueString(deployment().name, location)}-${hub.key}-nafs' + params: { + subnetName: 'AzureFirewallSubnet' + virtualNetworkName: hub.key + } + dependsOn: [hubVirtualNetwork] + } +] + +@batchSize(1) +module hubAzureFirewallSubnetAssociation 'modules/subnets.bicep' = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): if (hub.value.enableAzureFirewall) { + name: '${uniqueString(deployment().name, location)}-${hub.key}-nafsa' + params: { + name: 'AzureFirewallSubnet' + virtualNetworkName: hub.key + addressPrefix: hubAzureFirewallSubnet[index].outputs.addressPrefix + routeTableResourceId: hubRouteTable[index].outputs.resourceId + } + dependsOn: [hubAzureFirewallSubnet, hubAzureFirewall, hubVirtualNetwork] + } +] + +// +// Add your resources here +// + +// ============ // +// Outputs // +// ============ // + +@description('Array of hub virtual network resources.') +output hubVirtualNetworks object[] = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): { + resourceGroupName: hubVirtualNetwork[index].outputs.resourceGroupName + location: hubVirtualNetwork[index].outputs.location + name: hubVirtualNetwork[index].outputs.name + resourceId: hubVirtualNetwork[index].outputs.resourceId + } +] + +@description('Array of hub bastion resources.') +output hubBastions object[] = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): (hub.value.enableBastion) + ? { + resourceGroupName: hubBastion[index].outputs.resourceGroupName + location: hubBastion[index].outputs.location + name: hubBastion[index].outputs.name + resourceId: hubBastion[index].outputs.resourceId + } + : {} +] + +@description('Array of hub Azure Firewall resources.') +output hubAzureFirewalls object[] = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): (hub.value.enableAzureFirewall) + ? { + resourceGroupName: hubAzureFirewall[index].outputs.resourceGroupName + location: hubAzureFirewall[index].outputs.location + name: hubAzureFirewall[index].outputs.name + resourceId: hubAzureFirewall[index].outputs.resourceId + } + : {} +] + +@description('The subnets of the hub virtual network.') +output hubVirtualNetworkSubnets array = [ + for (hub, index) in items(hubVirtualNetworks ?? {}): hubVirtualNetwork[index].outputs.subnetNames +] + +@description('The resource group the resources were deployed into.') +output resourceGroupName string = resourceGroup().name + +// ================ // +// Definitions // +// ================ // +// +// Add your User-defined-types here, if any +// + +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('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @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? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type hubVirtualNetworkType = { + @description('Required. The hub virtual networks to create.') + *: { + @description('Required. The address prefixes for the virtual network.') + addressPrefixes: array + + @description('Optional. The Azure Firewall config.') + azureFirewallSettings: azureFirewallType? + + @description('Optional. The Azure Bastion config.') + bastionHost: { + @description('Optional. Enable/Disable copy/paste functionality.') + disableCopyPaste: bool? + + @description('Optional. Enable/Disable file copy functionality.') + enableFileCopy: bool? + + @description('Optional. Enable/Disable IP connect functionality.') + enableIpConnect: bool? + + @description('Optional. Enable/Disable shareable link functionality.') + enableShareableLink: bool? + + @description('Optional. The number of scale units for the Bastion host. Defaults to 4.') + scaleUnits: int? + + @description('Optional. The SKU name of the Bastion host. Defaults to Standard.') + skuName: string? + }? + + @description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? + + @description('Optional. Enable/Disable Azure Bastion for the virtual network.') + enableBastion: bool? + + @description('Optional. Enable/Disable Azure Firewall for the virtual network.') + enableAzureFirewall: bool? + + @description('Optional. The location of the virtual network. Defaults to the location of the resource group.') + location: string? + + @description('Optional. The lock settings of the virtual network.') + lock: lockType? + + @description('Optional. The diagnostic settings of the virtual network.') + diagnosticSettings: diagnosticSettingType? + + @description('Optional. The DDoS protection plan resource ID.') + ddosProtectionPlanResourceId: string? + + @description('Optional. The DNS servers of the virtual network.') + dnsServers: array? + + @description('Optional. The flow timeout in minutes.') + flowTimeoutInMinutes: int? + + @description('Optional. Enable/Disable peering for the virtual network.') + enablePeering: bool? + + @description('Optional. The peerings of the virtual network.') + peeringSettings: peeringSettingsType? + + @description('Optional. The role assignments to create.') + roleAssignments: roleAssignmentType? + + @description('Optional. Routes to add to the virtual network route table.') + routes: array? + + @description('Optional. The subnets of the virtual network.') + subnets: array? + + @description('Optional. The tags of the virtual network.') + tags: object? + + @description('Optional. Enable/Disable VNet encryption.') + vnetEncryption: bool? + + @description('Optional. The VNet encryption enforcement settings of the virtual network.') + vnetEncryptionEnforcement: string? + } +}? + +type peeringSettingsType = { + @description('Optional. Allow forwarded traffic.') + allowForwardedTraffic: bool? + + @description('Optional. Allow gateway transit.') + allowGatewayTransit: bool? + + @description('Optional. Allow virtual network access.') + allowVirtualNetworkAccess: bool? + + @description('Optional. Use remote gateways.') + useRemoteGateways: bool? + + @description('Optional. Remote virtual network name.') + remoteVirtualNetworkName: string? +}[]? + +type azureFirewallType = { + @description('Optional. Hub IP addresses.') + hubIpAddresses: object? + + @description('Optional. Virtual Hub ID.') + virtualHub: string? + + @description('Optional. Additional public IP configurations.') + additionalPublicIpConfigurations: array? + + @description('Optional. Application rule collections.') + applicationRuleCollections: array? + + @description('Optional. Azure Firewall SKU.') + azureSkuTier: string? + + @description('Optional. Diagnostic settings.') + diagnosticSettings: diagnosticSettingType? + + @description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? + + @description('Optional. Firewall policy ID.') + firewallPolicyId: string? + + @description('Optional. The location of the virtual network. Defaults to the location of the resource group.') + location: string? + + @description('Optional. Lock settings.') + lock: lockType? + + @description('Optional. Management IP address configuration.') + managementIPAddressObject: object? + + @description('Optional. Management IP resource ID.') + managementIPResourceID: string? + + @description('Optional. NAT rule collections.') + natRuleCollections: array? + + @description('Optional. Network rule collections.') + networkRuleCollections: array? + + @description('Optional. Public IP address object.') + publicIPAddressObject: object? + + @description('Optional. Public IP resource ID.') + publicIPResourceID: string? + + @description('Optional. Role assignments.') + roleAssignments: roleAssignmentType? + + @description('Optional. Tags of the resource.') + tags: object? + + @description('Optional. Threat Intel mode.') + threatIntelMode: string? + + @description('Optional. Zones.') + zones: int[]? +}? diff --git a/avm/ptn/network/hub-networking/main.json b/avm/ptn/network/hub-networking/main.json new file mode 100644 index 0000000000..6cac966757 --- /dev/null +++ b/avm/ptn/network/hub-networking/main.json @@ -0,0 +1,6896 @@ +{ + "$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.30.3.12046", + "templateHash": "8969613921663763778" + }, + "name": "Hub Networking", + "description": "This module is designed to simplify the creation of multi-region hub networks in Azure. It will create a number of virtual networks and subnets, and optionally peer them together in a mesh topology with routing.", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.value." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "hubVirtualNetworkType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "object", + "properties": { + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. The address prefixes for the virtual network." + } + }, + "azureFirewallSettings": { + "$ref": "#/definitions/azureFirewallType", + "nullable": true, + "metadata": { + "description": "Optional. The Azure Firewall config." + } + }, + "bastionHost": { + "type": "object", + "properties": { + "disableCopyPaste": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable copy/paste functionality." + } + }, + "enableFileCopy": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable file copy functionality." + } + }, + "enableIpConnect": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable IP connect functionality." + } + }, + "enableShareableLink": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable shareable link functionality." + } + }, + "scaleUnits": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of scale units for the Bastion host. Defaults to 4." + } + }, + "skuName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SKU name of the Bastion host. Defaults to Standard." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The Azure Bastion config." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "enableBastion": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable Azure Bastion for the virtual network." + } + }, + "enableAzureFirewall": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable Azure Firewall for the virtual network." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location of the virtual network. Defaults to the location of the resource group." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the virtual network." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "nullable": true, + "metadata": { + "description": "Optional. The diagnostic settings of the virtual network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan resource ID." + } + }, + "dnsServers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The DNS servers of the virtual network." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The flow timeout in minutes." + } + }, + "enablePeering": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable peering for the virtual network." + } + }, + "peeringSettings": { + "$ref": "#/definitions/peeringSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The peerings of the virtual network." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. The role assignments to create." + } + }, + "routes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Routes to add to the virtual network route table." + } + }, + "subnets": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The subnets of the virtual network." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the virtual network." + } + }, + "vnetEncryption": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable VNet encryption." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VNet encryption enforcement settings of the virtual network." + } + } + }, + "metadata": { + "description": "Required. The hub virtual networks to create." + } + }, + "nullable": true + }, + "peeringSettingsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allow forwarded traffic." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allow gateway transit." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Allow virtual network access." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Use remote gateways." + } + }, + "remoteVirtualNetworkName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Remote virtual network name." + } + } + } + }, + "nullable": true + }, + "azureFirewallType": { + "type": "object", + "properties": { + "hubIpAddresses": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Hub IP addresses." + } + }, + "virtualHub": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Virtual Hub ID." + } + }, + "additionalPublicIpConfigurations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Additional public IP configurations." + } + }, + "applicationRuleCollections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application rule collections." + } + }, + "azureSkuTier": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure Firewall SKU." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "nullable": true, + "metadata": { + "description": "Optional. Diagnostic settings." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "firewallPolicyId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Firewall policy ID." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location of the virtual network. Defaults to the location of the resource group." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. Lock settings." + } + }, + "managementIPAddressObject": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Management IP address configuration." + } + }, + "managementIPResourceID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Management IP resource ID." + } + }, + "natRuleCollections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. NAT rule collections." + } + }, + "networkRuleCollections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Network rule collections." + } + }, + "publicIPAddressObject": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Public IP address object." + } + }, + "publicIPResourceID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Public IP resource ID." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Role assignments." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "threatIntelMode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Threat Intel mode." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Zones." + } + } + }, + "nullable": true + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "hubVirtualNetworks": { + "$ref": "#/definitions/hubVirtualNetworkType", + "metadata": { + "description": "Optional. A map of the hub virtual networks to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "hubVirtualNetworkPeerings", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", + "input": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex('hubVirtualNetworkPeerings')].value, 'peeringSettings'), createArray())]" + } + ] + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.ptn.network-hubnetworking.{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" + } + } + } + } + }, + "hubVirtualNetworkPeer_local": { + "copy": { + "name": "hubVirtualNetworkPeer_local", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]" + }, + "condition": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enablePeering]", + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + }, + "hubVirtualNetworkPeering": { + "copy": { + "name": "hubVirtualNetworkPeering", + "count": "[length(coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray()))]" + }, + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}-to-{2}-peering', items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key, items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key, coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray())[copyIndex()].remoteVirtualNetworkName)]", + "properties": { + "allowForwardedTraffic": "[coalesce(coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray())[copyIndex()].allowForwardedTraffic, false())]", + "allowGatewayTransit": "[coalesce(coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray())[copyIndex()].allowGatewayTransit, false())]", + "allowVirtualNetworkAccess": "[coalesce(coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray())[copyIndex()].allowVirtualNetworkAccess, true())]", + "useRemoteGateways": "[coalesce(coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray())[copyIndex()].useRemoteGateways, false())]", + "remoteVirtualNetwork": { + "id": "[reference(format('hubVirtualNetworkPeer_remote[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "dependsOn": [ + "hubVirtualNetwork", + "[format('hubVirtualNetworkPeer_local[{0}]', copyIndex())]", + "[format('hubVirtualNetworkPeer_local[{0}]', copyIndex())]", + "[format('hubVirtualNetworkPeer_remote[{0}]', copyIndex())]" + ] + }, + "hubRoute": { + "copy": { + "name": "hubRoute", + "count": "[length(coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray()))]" + }, + "type": "Microsoft.Network/routeTables/routes", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}-to-{2}-route', items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key, items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key, coalesce(flatten(variables('hubVirtualNetworkPeerings')), createArray())[copyIndex()].remoteVirtualNetworkName)]", + "properties": { + "addressPrefix": "[reference(format('hubVirtualNetworkPeer_remote[{0}]', copyIndex())).outputs.addressPrefix.value]", + "nextHopType": "VirtualAppliance", + "nextHopIpAddress": "[reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.privateIp.value]" + }, + "dependsOn": [ + "[format('hubAzureFirewall[{0}]', copyIndex())]", + "[format('hubVirtualNetworkPeer_local[{0}]', copyIndex())]", + "[format('hubVirtualNetworkPeer_local[{0}]', copyIndex())]", + "[format('hubVirtualNetworkPeer_remote[{0}]', copyIndex())]", + "hubVirtualNetworkPeering" + ] + }, + "hubVirtualNetwork": { + "copy": { + "name": "hubVirtualNetwork", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-nvn', uniqueString(deployment().name, parameters('location')), items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + }, + "addressPrefixes": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.addressPrefixes]" + }, + "ddosProtectionPlanResourceId": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'ddosProtectionPlanResourceId'), '')]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'diagnosticSettings'), createArray())]" + }, + "dnsServers": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'dnsServers'), createArray())]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'enableTelemetry'), true())]" + }, + "flowTimeoutInMinutes": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'flowTimeoutInMinutes'), 0)]" + }, + "location": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'location'), '')]" + }, + "lock": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'lock'), createObject())]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'roleAssignments'), createArray())]" + }, + "subnets": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'subnets'), createArray())]" + }, + "tags": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'tags'), createObject())]" + }, + "vnetEncryption": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'vnetEncryption'), false())]" + }, + "vnetEncryptionEnforcement": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'vnetEncryptionEnforcement'), '')]" + } + }, + "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.29.47.4906", + "templateHash": "15949466154563447171" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "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." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": { + "addressPrefixes": "[parameters('addressPrefixes')]" + }, + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" + } + }, + "virtualNetwork_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/virtualNetworks/{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": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + } + }, + "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.29.47.4906", + "templateHash": "5699372618313647761" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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", + "metadata": { + "description": "Requird. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" + } + } + } + } + }, + "hubVirtualNetworkPeer_remote": { + "copy": { + "name": "hubVirtualNetworkPeer_remote", + "count": "[length(flatten(variables('hubVirtualNetworkPeerings')))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-nvnp', uniqueString(deployment().name, parameters('location')), flatten(variables('hubVirtualNetworkPeerings'))[copyIndex()].remoteVirtualNetworkName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[flatten(variables('hubVirtualNetworkPeerings'))[copyIndex()].remoteVirtualNetworkName]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "5568850224456572684" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address space of the virtual network." + }, + "value": "[reference(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), '2024-01-01').addressSpace.addressPrefixes[0]]" + } + } + } + }, + "dependsOn": [ + "hubVirtualNetwork" + ] + }, + "hubRouteTable": { + "copy": { + "name": "hubRouteTable", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-nrt', uniqueString(deployment().name, parameters('location')), items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + }, + "location": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'location'), parameters('location'))]" + }, + "disableBgpRoutePropagation": { + "value": true + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'enableTelemetry'), true())]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'roleAssignments'), createArray())]" + }, + "routes": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'routes'), createArray())]" + }, + "tags": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'tags'), createObject())]" + } + }, + "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.29.47.4906", + "templateHash": "5827817137345359685" + }, + "name": "Route Tables", + "description": "This module deploys a User Defined Route Table (UDR).", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "routeType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the route." + } + }, + "properties": { + "type": "object", + "properties": { + "nextHopType": { + "type": "string", + "allowedValues": [ + "Internet", + "None", + "VirtualAppliance", + "VirtualNetworkGateway", + "VnetLocal" + ], + "metadata": { + "description": "Required. The type of Azure hop the packet should be sent to." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The destination CIDR to which the route applies." + } + }, + "hasBgpOverride": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. A value indicating whether this route overrides overlapping BGP routes regardless of LPM." + } + }, + "nextHopIpAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The IP address packets should be forwarded to. Next hop values are only allowed in routes where the next hop type is VirtualAppliance." + } + } + }, + "metadata": { + "description": "Required. Properties of the route." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name given for the hub route table." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "routes": { + "$ref": "#/definitions/routeType", + "metadata": { + "description": "Optional. An array of routes to be established within the hub route table." + } + }, + "disableBgpRoutePropagation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Switch to disable BGP route propagation." + } + }, + "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": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[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": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-routetable.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "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" + } + } + } + } + }, + "routeTable": { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": "[parameters('routes')]", + "disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]" + } + }, + "routeTable_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/routeTables/{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": [ + "routeTable" + ] + }, + "routeTable_roleAssignments": { + "copy": { + "name": "routeTable_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/routeTables/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/routeTables', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "routeTable" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the route table was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the route table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the route table." + }, + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('routeTable', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "hubVirtualNetwork" + ] + }, + "hubBastion": { + "copy": { + "name": "hubBastion", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]" + }, + "condition": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableBastion]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-nbh', uniqueString(deployment().name, parameters('location')), items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + }, + "virtualNetworkResourceId": { + "value": "[reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.resourceId.value]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'diagnosticSettings'), createArray())]" + }, + "disableCopyPaste": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'bastionHost'), 'disableCopyPaste'), true())]" + }, + "enableFileCopy": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'bastionHost'), 'enableFileCopy'), false())]" + }, + "enableIpConnect": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'bastionHost'), 'enableIpConnect'), false())]" + }, + "enableShareableLink": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'bastionHost'), 'enableShareableLink'), false())]" + }, + "location": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'location'), parameters('location'))]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'enableTelemetry'), true())]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'roleAssignments'), createArray())]" + }, + "scaleUnits": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'bastionHost'), 'scaleUnits'), 4)]" + }, + "skuName": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'bastionHost'), 'skuName'), 'Standard')]" + }, + "tags": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'tags'), createObject())]" + } + }, + "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.29.47.4906", + "templateHash": "11368267491813619372" + }, + "name": "Bastion Hosts", + "description": "This module deploys a Bastion Host.", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Bastion resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Shared services Virtual Network resource Id." + } + }, + "bastionSubnetPublicIpResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet." + } + }, + "publicIPAddressObject": { + "type": "object", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. The SKU of this Bastion Host." + } + }, + "disableCopyPaste": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Copy Paste." + } + }, + "enableFileCopy": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Choose to disable or enable File Copy." + } + }, + "enableIpConnect": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable IP Connect." + } + }, + "enableKerberos": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Kerberos authentication." + } + }, + "enableShareableLink": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Choose to disable or enable Shareable Link." + } + }, + "scaleUnits": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The scale units for the Bastion Host resource." + } + }, + "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": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "azureBastion": { + "type": "Microsoft.Network/bastionHosts", + "apiVersion": "2022-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "properties": "[union(createObject('scaleUnits', if(equals(parameters('skuName'), 'Basic'), 2, parameters('scaleUnits')), 'ipConfigurations', createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value)))))), 'enableKerberos', parameters('enableKerberos')), if(equals(parameters('skuName'), 'Standard'), createObject('enableTunneling', equals(parameters('skuName'), 'Standard'), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()))]", + "dependsOn": [ + "publicIPAddress" + ] + }, + "azureBastion_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/bastionHosts/{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": [ + "azureBastion" + ] + }, + "azureBastion_diagnosticSettings": { + "copy": { + "name": "azureBastion_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "azureBastion_roleAssignments": { + "copy": { + "name": "azureBastion_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureBastion" + ] + }, + "publicIPAddress": { + "condition": "[empty(parameters('bastionSubnetPublicIpResourceId'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Bastion-PIP', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "publicIPAddressVersion": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" + }, + "publicIPAllocationMethod": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" + }, + "publicIpPrefixResourceId": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" + }, + "skuName": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" + }, + "skuTier": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'zones')]" + } + }, + "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.29.47.4906", + "templateHash": "14450344965065009842" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_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/publicIPAddresses/{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": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure Bastion was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name the Azure Bastion." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID the Azure Bastion." + }, + "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureBastion', '2022-11-01', 'full').location]" + }, + "ipConfAzureBastionSubnet": { + "type": "object", + "metadata": { + "description": "The Public IPconfiguration object for the AzureBastionSubnet." + }, + "value": "[reference('azureBastion').ipConfigurations[0]]" + } + } + } + }, + "dependsOn": [ + "hubVirtualNetwork" + ] + }, + "hubAzureFirewall": { + "copy": { + "name": "hubAzureFirewall", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]" + }, + "condition": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableAzureFirewall]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-naf', uniqueString(deployment().name, parameters('location')), items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + }, + "hubIPAddresses": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'hubIpAddresses'), createObject())]" + }, + "virtualHubId": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'virtualHub'), '')]" + }, + "virtualNetworkResourceId": { + "value": "[coalesce(reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.resourceId.value, '')]" + }, + "additionalPublicIpConfigurations": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'additionalPublicIpConfigurations'), createArray())]" + }, + "applicationRuleCollections": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'applicationRuleCollections'), createArray())]" + }, + "azureSkuTier": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'azureSkuTier'), createObject())]" + }, + "diagnosticSettings": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'diagnosticSettings'), createArray())]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'enableTelemetry'), true())]" + }, + "firewallPolicyId": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'firewallPolicyId'), '')]" + }, + "location": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'location'), parameters('location'))]" + }, + "lock": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'lock'), createObject())]" + }, + "managementIPAddressObject": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'managementIPAddressObject'), createObject())]" + }, + "managementIPResourceID": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'managementIPResourceID'), '')]" + }, + "natRuleCollections": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'natRuleCollections'), createArray())]" + }, + "networkRuleCollections": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'networkRuleCollections'), createArray())]" + }, + "publicIPAddressObject": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'publicIPAddressObject'), createObject())]" + }, + "publicIPResourceID": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'publicIPResourceID'), '')]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'roleAssignments'), createArray())]" + }, + "tags": { + "value": "[coalesce(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'tags'), createObject())]" + }, + "threatIntelMode": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'threatIntelMode'), '')]" + }, + "zones": { + "value": "[coalesce(tryGet(tryGet(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value, 'azureFirewallSettings'), 'zones'), createArray())]" + } + }, + "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.29.47.4906", + "templateHash": "15791050653269307918" + }, + "name": "Azure Firewalls", + "description": "This module deploys an Azure Firewall.", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "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": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Firewall." + } + }, + "azureSkuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Tier of an Azure Firewall." + } + }, + "virtualNetworkResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty." + } + }, + "publicIPResourceID": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet." + } + }, + "additionalPublicIpConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration." + } + }, + "publicIPAddressObject": { + "type": "object", + "defaultValue": { + "name": "[format('{0}-pip', parameters('name'))]" + }, + "metadata": { + "description": "Optional. Specifies the properties of the Public IP to create and be used by the Firewall, if no existing public IP was provided." + } + }, + "managementIPResourceID": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Management Public IP resource ID to associate to the AzureFirewallManagementSubnet. If empty, then the Management Public IP that is created as part of this module will be applied to the AzureFirewallManagementSubnet." + } + }, + "managementIPAddressObject": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Specifies the properties of the Management Public IP to create and be used by Azure Firewall. If it's not provided and managementIPResourceID is empty, a '-mip' suffix will be appended to the Firewall's name." + } + }, + "applicationRuleCollections": { + "$ref": "#/definitions/applicationRuleCollectionType", + "metadata": { + "description": "Optional. Collection of application rule collections used by Azure Firewall." + } + }, + "networkRuleCollections": { + "$ref": "#/definitions/networkRuleCollectionType", + "metadata": { + "description": "Optional. Collection of network rule collections used by Azure Firewall." + } + }, + "natRuleCollections": { + "$ref": "#/definitions/natRuleCollectionType", + "metadata": { + "description": "Optional. Collection of NAT rule collections used by Azure Firewall." + } + }, + "firewallPolicyId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the Firewall Policy that should be attached." + } + }, + "hubIPAddresses": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Conditional. IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied." + } + }, + "virtualHubId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Conditional. The virtualHub resource ID to which the firewall belongs. Required if `virtualNetworkId` is empty." + } + }, + "threatIntelMode": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Alert", + "Deny", + "Off" + ], + "metadata": { + "description": "Optional. The operation mode for Threat Intel." + } + }, + "zones": { + "type": "array", + "defaultValue": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. Zone numbers e.g. 1,2,3." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "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 Azure Firewall resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "additionalPublicIpConfigurationsVar", + "count": "[length(parameters('additionalPublicIpConfigurations'))]", + "input": { + "name": "[parameters('additionalPublicIpConfigurations')[copyIndex('additionalPublicIpConfigurationsVar')].name]", + "properties": { + "publicIPAddress": "[if(contains(parameters('additionalPublicIpConfigurations')[copyIndex('additionalPublicIpConfigurationsVar')], 'publicIPAddressResourceId'), createObject('id', parameters('additionalPublicIpConfigurations')[copyIndex('additionalPublicIpConfigurationsVar')].publicIPAddressResourceId), null())]" + } + } + }, + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "azureSkuName": "[if(empty(parameters('virtualNetworkResourceId')), 'AZFW_Hub', 'AZFW_VNet')]", + "requiresManagementIp": "[if(equals(parameters('azureSkuTier'), 'Basic'), true(), false())]", + "isCreateDefaultManagementIP": "[and(empty(parameters('managementIPResourceID')), variables('requiresManagementIp'))]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.network-azurefirewall.{0}.{1}', replace('0.5.0', '.', '-'), 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" + } + } + } + } + }, + "azureFirewall": { + "type": "Microsoft.Network/azureFirewalls", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "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', createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId'))), 'publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value)))), 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" + ] + }, + "azureFirewall_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/azureFirewalls/{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": [ + "azureFirewall" + ] + }, + "azureFirewall_diagnosticSettings": { + "copy": { + "name": "azureFirewall_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/azureFirewalls/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "azureFirewall" + ] + }, + "azureFirewall_roleAssignments": { + "copy": { + "name": "azureFirewall_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/azureFirewalls/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/azureFirewalls', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "azureFirewall" + ] + }, + "publicIPAddress": { + "condition": "[and(empty(parameters('publicIPResourceID')), equals(variables('azureSkuName'), 'AZFW_VNet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Firewall-PIP', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('publicIPAddressObject').name]" + }, + "publicIpPrefixResourceId": "[if(contains(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId'), if(not(empty(parameters('publicIPAddressObject').publicIPPrefixResourceId)), createObject('value', parameters('publicIPAddressObject').publicIPPrefixResourceId), createObject('value', '')), createObject('value', ''))]", + "publicIPAllocationMethod": "[if(contains(parameters('publicIPAddressObject'), 'publicIPAllocationMethod'), if(not(empty(parameters('publicIPAddressObject').publicIPAllocationMethod)), createObject('value', parameters('publicIPAddressObject').publicIPAllocationMethod), createObject('value', 'Static')), createObject('value', 'Static'))]", + "skuName": "[if(contains(parameters('publicIPAddressObject'), 'skuName'), if(not(empty(parameters('publicIPAddressObject').skuName)), createObject('value', parameters('publicIPAddressObject').skuName), createObject('value', 'Standard')), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('publicIPAddressObject'), 'skuTier'), if(not(empty(parameters('publicIPAddressObject').skuTier)), createObject('value', parameters('publicIPAddressObject').skuTier), createObject('value', 'Regional')), createObject('value', 'Regional'))]", + "roleAssignments": "[if(contains(parameters('publicIPAddressObject'), 'roleAssignments'), if(not(empty(parameters('publicIPAddressObject').roleAssignments)), createObject('value', parameters('publicIPAddressObject').roleAssignments), createObject('value', createArray())), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "lock": { + "value": "[parameters('lock')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[parameters('zones')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "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.29.47.4906", + "templateHash": "14450344965065009842" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_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/publicIPAddresses/{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": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + }, + "managementIPAddress": { + "condition": "[and(variables('isCreateDefaultManagementIP'), equals(variables('azureSkuName'), 'AZFW_VNet'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Firewall-MIP', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": "[if(contains(parameters('managementIPAddressObject'), 'name'), if(not(empty(parameters('managementIPAddressObject').name)), createObject('value', parameters('managementIPAddressObject').name), createObject('value', format('{0}-mip', parameters('name')))), createObject('value', format('{0}-mip', parameters('name'))))]", + "publicIpPrefixResourceId": "[if(contains(parameters('managementIPAddressObject'), 'managementIPPrefixResourceId'), if(not(empty(parameters('managementIPAddressObject').managementIPPrefixResourceId)), createObject('value', parameters('managementIPAddressObject').managementIPPrefixResourceId), createObject('value', '')), createObject('value', ''))]", + "publicIPAllocationMethod": "[if(contains(parameters('managementIPAddressObject'), 'managementIPAllocationMethod'), if(not(empty(parameters('managementIPAddressObject').managementIPAllocationMethod)), createObject('value', parameters('managementIPAddressObject').managementIPAllocationMethod), createObject('value', 'Static')), createObject('value', 'Static'))]", + "skuName": "[if(contains(parameters('managementIPAddressObject'), 'skuName'), if(not(empty(parameters('managementIPAddressObject').skuName)), createObject('value', parameters('managementIPAddressObject').skuName), createObject('value', 'Standard')), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('managementIPAddressObject'), 'skuTier'), if(not(empty(parameters('managementIPAddressObject').skuTier)), createObject('value', parameters('managementIPAddressObject').skuTier), createObject('value', 'Regional')), createObject('value', 'Regional'))]", + "roleAssignments": "[if(contains(parameters('managementIPAddressObject'), 'roleAssignments'), if(not(empty(parameters('managementIPAddressObject').roleAssignments)), createObject('value', parameters('managementIPAddressObject').roleAssignments), createObject('value', createArray())), createObject('value', createArray()))]", + "diagnosticSettings": { + "value": "[tryGet(parameters('managementIPAddressObject'), 'diagnosticSettings')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[coalesce(tryGet(parameters('managementIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": { + "value": "[parameters('zones')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('managementIPAddressObject'), 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "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.29.47.4906", + "templateHash": "14450344965065009842" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "dnsSettingsType": { + "type": "object", + "properties": { + "domainNameLabel": { + "type": "string", + "metadata": { + "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." + } + }, + "domainNameLabelScope": { + "type": "string", + "allowedValues": [ + "", + "NoReuse", + "ResourceGroupReuse", + "SubscriptionReuse", + "TenantReuse" + ], + "metadata": { + "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." + } + }, + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." + } + }, + "reverseFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." + } + } + } + }, + "ddosSettingsType": { + "type": "object", + "properties": { + "ddosProtectionPlan": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan associated with the public IP address." + } + }, + "protectionMode": { + "type": "string", + "allowedValues": [ + "Enabled" + ], + "metadata": { + "description": "Required. The DDoS protection policy customizations." + } + } + } + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Public IP Address." + } + }, + "publicIpPrefixResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." + } + }, + "publicIPAllocationMethod": { + "type": "string", + "defaultValue": "Static", + "allowedValues": [ + "Dynamic", + "Static" + ], + "metadata": { + "description": "Optional. The public IP address allocation method." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." + } + }, + "publicIPAddressVersion": { + "type": "string", + "defaultValue": "IPv4", + "allowedValues": [ + "IPv4", + "IPv6" + ], + "metadata": { + "description": "Optional. IP address version." + } + }, + "dnsSettings": { + "$ref": "#/definitions/dnsSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DNS settings of the public IP address." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Standard" + ], + "metadata": { + "description": "Optional. Name of a public IP address SKU." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Regional", + "allowedValues": [ + "Global", + "Regional" + ], + "metadata": { + "description": "Optional. Tier of a public IP address SKU." + } + }, + "ddosSettings": { + "$ref": "#/definitions/ddosSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The DDoS protection plan configuration associated with the public IP address." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "idleTimeoutInMinutes": { + "type": "int", + "defaultValue": 4, + "metadata": { + "description": "Optional. The idle timeout of the public IP address." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "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" + } + } + } + } + }, + "publicIpAddress": { + "type": "Microsoft.Network/publicIPAddresses", + "apiVersion": "2023-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", + "properties": { + "ddosSettings": "[parameters('ddosSettings')]", + "dnsSettings": "[parameters('dnsSettings')]", + "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", + "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", + "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", + "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", + "ipTags": null + } + }, + "publicIpAddress_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/publicIPAddresses/{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": [ + "publicIpAddress" + ] + }, + "publicIpAddress_roleAssignments": { + "copy": { + "name": "publicIpAddress_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + }, + "publicIpAddress_diagnosticSettings": { + "copy": { + "name": "publicIpAddress_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "publicIpAddress" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the public IP address was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the public IP address." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the public IP address." + }, + "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" + }, + "ipAddress": { + "type": "string", + "metadata": { + "description": "The public IP address of the public IP address resource." + }, + "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure Firewall." + }, + "value": "[resourceId('Microsoft.Network/azureFirewalls', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Azure Firewall." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the Azure firewall was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "privateIp": { + "type": "string", + "metadata": { + "description": "The private IP of the Azure firewall." + }, + "value": "[if(contains(reference('azureFirewall'), 'ipConfigurations'), reference('azureFirewall').ipConfigurations[0].properties.privateIPAddress, '')]" + }, + "ipConfAzureFirewallSubnet": { + "type": "object", + "metadata": { + "description": "The Public IP configuration object for the Azure Firewall Subnet." + }, + "value": "[if(contains(reference('azureFirewall'), 'ipConfigurations'), reference('azureFirewall').ipConfigurations[0], createObject())]" + }, + "applicationRuleCollections": { + "type": "array", + "metadata": { + "description": "List of Application Rule Collections used by Azure Firewall." + }, + "value": "[coalesce(parameters('applicationRuleCollections'), createArray())]" + }, + "networkRuleCollections": { + "type": "array", + "metadata": { + "description": "List of Network Rule Collections used by Azure Firewall." + }, + "value": "[coalesce(parameters('networkRuleCollections'), createArray())]" + }, + "natRuleCollections": { + "type": "array", + "metadata": { + "description": "List of NAT rule collections used by Azure Firewall." + }, + "value": "[coalesce(parameters('natRuleCollections'), createArray())]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('azureFirewall', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "hubVirtualNetwork" + ] + }, + "hubAzureFirewallSubnet": { + "copy": { + "name": "hubAzureFirewallSubnet", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]" + }, + "condition": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableAzureFirewall]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-nafs', uniqueString(deployment().name, parameters('location')), items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "subnetName": { + "value": "AzureFirewallSubnet" + }, + "virtualNetworkName": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16563975082451649304" + }, + "name": "Existing Virtual Network Subnets", + "description": "This module retrieves an existing Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "subnetName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the subnet." + } + }, + "virtualNetworkName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the virtual network." + } + } + }, + "resources": [], + "outputs": { + "subnetId": { + "type": "string", + "metadata": { + "description": "Subnet ID" + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Subnet address prefix" + }, + "value": "[reference(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName')), '2024-01-01').addressPrefix]" + } + } + } + }, + "dependsOn": [ + "hubVirtualNetwork" + ] + }, + "hubAzureFirewallSubnetAssociation": { + "copy": { + "name": "hubAzureFirewallSubnetAssociation", + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", + "mode": "serial", + "batchSize": 1 + }, + "condition": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableAzureFirewall]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-nafsa', uniqueString(deployment().name, parameters('location')), items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "AzureFirewallSubnet" + }, + "virtualNetworkName": { + "value": "[items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].key]" + }, + "addressPrefix": { + "value": "[reference(format('hubAzureFirewallSubnet[{0}]', copyIndex())).outputs.addressPrefix.value]" + }, + "routeTableResourceId": { + "value": "[reference(format('hubRouteTable[{0}]', copyIndex())).outputs.resourceId.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.30.3.12046", + "templateHash": "10294962787410461549" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "Required. The address prefix for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The delegations to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of address prefixes for the subnet." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "ipAllocations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of IpAllocation which reference this subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-11-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "addressPrefix": "[parameters('addressPrefix')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "serviceEndpoints": "[parameters('serviceEndpoints')]", + "delegations": "[parameters('delegations')]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "ipAllocations": "[parameters('ipAllocations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the subnet was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "subnetName": { + "type": "string", + "metadata": { + "description": "The name of the subnet." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the subnet." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "subnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[reference('subnet').addressPrefix]" + }, + "subnetAddressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" + } + } + } + }, + "dependsOn": [ + "hubAzureFirewall", + "hubAzureFirewallSubnet", + "[format('hubRouteTable[{0}]', copyIndex())]", + "hubVirtualNetwork" + ] + } + }, + "outputs": { + "hubVirtualNetworks": { + "type": "array", + "items": { + "type": "object" + }, + "metadata": { + "description": "Array of hub virtual network resources." + }, + "copy": { + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", + "input": { + "resourceGroupName": "[reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.resourceGroupName.value]", + "location": "[reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.location.value]", + "name": "[reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.resourceId.value]" + } + } + }, + "hubBastions": { + "type": "array", + "items": { + "type": "object" + }, + "metadata": { + "description": "Array of hub bastion resources." + }, + "copy": { + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", + "input": "[if(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableBastion, createObject('resourceGroupName', reference(format('hubBastion[{0}]', copyIndex())).outputs.resourceGroupName.value, 'location', reference(format('hubBastion[{0}]', copyIndex())).outputs.location.value, 'name', reference(format('hubBastion[{0}]', copyIndex())).outputs.name.value, 'resourceId', reference(format('hubBastion[{0}]', copyIndex())).outputs.resourceId.value), createObject())]" + } + }, + "hubAzureFirewalls": { + "type": "array", + "items": { + "type": "object" + }, + "metadata": { + "description": "Array of hub Azure Firewall resources." + }, + "copy": { + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", + "input": "[if(items(coalesce(parameters('hubVirtualNetworks'), createObject()))[copyIndex()].value.enableAzureFirewall, createObject('resourceGroupName', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.resourceGroupName.value, 'location', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.location.value, 'name', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.name.value, 'resourceId', reference(format('hubAzureFirewall[{0}]', copyIndex())).outputs.resourceId.value), createObject())]" + } + }, + "hubVirtualNetworkSubnets": { + "type": "array", + "metadata": { + "description": "The subnets of the hub virtual network." + }, + "copy": { + "count": "[length(items(coalesce(parameters('hubVirtualNetworks'), createObject())))]", + "input": "[reference(format('hubVirtualNetwork[{0}]', copyIndex())).outputs.subnetNames.value]" + } + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the resources were deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/network/hub-networking/modules/getSubnet.bicep b/avm/ptn/network/hub-networking/modules/getSubnet.bicep new file mode 100644 index 0000000000..02a646a91c --- /dev/null +++ b/avm/ptn/network/hub-networking/modules/getSubnet.bicep @@ -0,0 +1,23 @@ +metadata name = 'Existing Virtual Network Subnets' +metadata description = 'This module retrieves an existing Virtual Network Subnet.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. The name of the subnet.') +param subnetName string = '' + +@description('Optional. The name of the virtual network.') +param virtualNetworkName string = '' + +resource vnet 'Microsoft.Network/virtualNetworks@2024-01-01' existing = { + name: virtualNetworkName + + resource subnet 'subnets@2024-01-01' existing = { + name: subnetName + } +} + +@description('Subnet ID') +output subnetId string = vnet::subnet.id + +@description('Subnet address prefix') +output addressPrefix string = vnet::subnet.properties.addressPrefix diff --git a/avm/ptn/network/hub-networking/modules/subnets.bicep b/avm/ptn/network/hub-networking/modules/subnets.bicep new file mode 100644 index 0000000000..49e9a4c21d --- /dev/null +++ b/avm/ptn/network/hub-networking/modules/subnets.bicep @@ -0,0 +1,185 @@ +metadata name = 'Virtual Network Subnets' +metadata description = 'This module deploys a Virtual Network Subnet.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The Name of the subnet resource.') +param name string + +@description('Required. The name of the parent virtual network. Required if the template is used in a standalone deployment.') +param virtualNetworkName string + +@description('Required. The address prefix for the subnet.') +param addressPrefix string + +@description('Optional. The resource ID of the network security group to assign to the subnet.') +param networkSecurityGroupResourceId string = '' + +@description('Optional. The resource ID of the route table to assign to the subnet.') +param routeTableResourceId string = '' + +@description('Optional. The service endpoints to enable on the subnet.') +param serviceEndpoints array = [] + +@description('Optional. The delegations to enable on the subnet.') +param delegations array = [] + +@description('Optional. The resource ID of the NAT Gateway to use for the subnet.') +param natGatewayResourceId string = '' + +@description('Optional. Enable or disable apply network policies on private endpoint in the subnet.') +@allowed([ + 'Disabled' + 'Enabled' + '' +]) +param privateEndpointNetworkPolicies string = '' + +@description('Optional. Enable or disable apply network policies on private link service in the subnet.') +@allowed([ + 'Disabled' + 'Enabled' + '' +]) +param privateLinkServiceNetworkPolicies string = '' + +@description('Optional. List of address prefixes for the subnet.') +param addressPrefixes array = [] + +@description('Optional. Application gateway IP configurations of virtual network resource.') +param applicationGatewayIPConfigurations array = [] + +@description('Optional. Array of IpAllocation which reference this subnet.') +param ipAllocations array = [] + +@description('Optional. An array of service endpoint policies.') +param serviceEndpointPolicies array = [] + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +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' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-11-01' existing = { + name: virtualNetworkName +} + +resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-11-01' = { + name: name + parent: virtualNetwork + properties: { + addressPrefix: addressPrefix + networkSecurityGroup: !empty(networkSecurityGroupResourceId) + ? { + id: networkSecurityGroupResourceId + } + : null + routeTable: !empty(routeTableResourceId) + ? { + id: routeTableResourceId + } + : null + natGateway: !empty(natGatewayResourceId) + ? { + id: natGatewayResourceId + } + : null + serviceEndpoints: serviceEndpoints + delegations: delegations + privateEndpointNetworkPolicies: !empty(privateEndpointNetworkPolicies) ? any(privateEndpointNetworkPolicies) : null + privateLinkServiceNetworkPolicies: !empty(privateLinkServiceNetworkPolicies) + ? any(privateLinkServiceNetworkPolicies) + : null + addressPrefixes: addressPrefixes + applicationGatewayIPConfigurations: applicationGatewayIPConfigurations + ipAllocations: ipAllocations + serviceEndpointPolicies: serviceEndpointPolicies + } +} + +resource subnet_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(subnet.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + 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: subnet + } +] + +@description('The resource group the subnet was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the subnet.') +output subnetName string = subnet.name + +@description('The resource ID of the subnet.') +output resourceId string = subnet.id + +@description('The address prefix for the subnet.') +output subnetAddressPrefix string = subnet.properties.addressPrefix + +@description('List of address prefixes for the subnet.') +output subnetAddressPrefixes array = !empty(addressPrefixes) ? subnet.properties.addressPrefixes : [] + +// =============== // +// Definitions // +// =============== // + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @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/ptn/network/hub-networking/modules/vnets.bicep b/avm/ptn/network/hub-networking/modules/vnets.bicep new file mode 100644 index 0000000000..78d6048a3f --- /dev/null +++ b/avm/ptn/network/hub-networking/modules/vnets.bicep @@ -0,0 +1,22 @@ +metadata name = 'Virtual Networks' +metadata description = 'This module deploys a Virtual Network.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the parent virtual network. Required if the template is used in a standalone deployment.') +param name string + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' existing = { + name: name +} + +@description('The resource group the virtual network peering was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the virtual network peering.') +output name string = virtualNetwork.name + +@description('The resource ID of the virtual network peering.') +output resourceId string = virtualNetwork.id + +@description('The address space of the virtual network.') +output addressPrefix string = virtualNetwork.properties.addressSpace.addressPrefixes[0] diff --git a/avm/ptn/network/hub-networking/tests/e2e/defaults/main.test.bicep b/avm/ptn/network/hub-networking/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..86181df221 --- /dev/null +++ b/avm/ptn/network/hub-networking/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.hub-networking-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nhnmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + } + } +] diff --git a/avm/ptn/network/hub-networking/tests/e2e/max/main.test.bicep b/avm/ptn/network/hub-networking/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..5ff56e9d23 --- /dev/null +++ b/avm/ptn/network/hub-networking/tests/e2e/max/main.test.bicep @@ -0,0 +1,225 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.hub-networking-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nhnmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' +var addressPrefix2 = '10.1.0.0/16' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + // You parameters go here + location: resourceLocation + hubVirtualNetworks: { + hub1: { + addressPrefixes: array(addressPrefix) + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: resourceLocation + publicIPAddressObject: { + name: 'hub1-waf-pip' + } + threatIntelMode: 'Alert' + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + dnsServers: ['10.0.1.4', '10.0.1.5'] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + useRemoteGateways: false + remoteVirtualNetworkName: 'hub2' + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + name: 'GatewaySubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + { + name: 'AzureFirewallSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + { + name: 'AzureBastionSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 2) + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + hub2: { + addressPrefixes: array(addressPrefix2) + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: resourceLocation + publicIPAddressObject: { + name: 'hub2-waf-pip' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: false + flowTimeoutInMinutes: 10 + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'hub2Lock' + } + peeringSettings: [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + useRemoteGateways: false + remoteVirtualNetworkName: 'hub1' + } + ] + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + name: 'GatewaySubnet' + addressPrefix: cidrSubnet(addressPrefix2, 26, 0) + } + { + name: 'AzureFirewallSubnet' + addressPrefix: cidrSubnet(addressPrefix2, 26, 1) + } + { + name: 'AzureBastionSubnet' + addressPrefix: cidrSubnet(addressPrefix2, 26, 2) + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + } + } +] diff --git a/avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep b/avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep new file mode 100644 index 0000000000..12d7a9613a --- /dev/null +++ b/avm/ptn/network/hub-networking/tests/e2e/no-addons/main.test.bicep @@ -0,0 +1,124 @@ +targetScope = 'subscription' + +metadata name = 'No Addons' +metadata description = 'This instance deploys the module with no add-ons (Firewall / Bastion) enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.hub-networking-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nhnnadd' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + // You parameters go here + location: resourceLocation + hubVirtualNetworks: { + hub1: { + addressPrefixes: array(addressPrefix) + enableAzureFirewall: false + enableBastion: false + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + dnsServers: ['10.0.1.6', '10.0.1.7'] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + name: 'GatewaySubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + { + name: 'AzureFirewallSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + { + name: 'AzureBastionSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 2) + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + } + } +] diff --git a/avm/ptn/network/hub-networking/tests/e2e/waf-aligned/main.test.bicep b/avm/ptn/network/hub-networking/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..693e68fe09 --- /dev/null +++ b/avm/ptn/network/hub-networking/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,146 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.hub-networking-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nhnwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: resourceGroupName + location: resourceLocation +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +var addressPrefix = '10.0.0.0/16' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + // You parameters go here + location: resourceLocation + hubVirtualNetworks: { + hub1: { + addressPrefixes: array(addressPrefix) + azureFirewallSettings: { + azureSkuTier: 'Standard' + enableTelemetry: true + location: resourceLocation + publicIPAddressObject: { + name: 'hub1PublicIp' + } + threatIntelMode: 'Alert' + zones: [ + 1 + 2 + 3 + ] + } + bastionHost: { + disableCopyPaste: true + enableFileCopy: false + enableIpConnect: false + enableShareableLink: false + scaleUnits: 2 + skuName: 'Standard' + } + enableAzureFirewall: true + enableBastion: true + enablePeering: false + enableTelemetry: true + flowTimeoutInMinutes: 30 + dnsServers: ['10.0.1.6', '10.0.1.7'] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'hub1Lock' + } + routes: [ + { + name: 'defaultRoute' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'Internet' + } + } + ] + subnets: [ + { + name: 'GatewaySubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + { + name: 'AzureFirewallSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + { + name: 'AzureBastionSubnet' + addressPrefix: cidrSubnet(addressPrefix, 26, 2) + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + vnetEncryption: false + vnetEncryptionEnforcement: 'AllowUnencrypted' + } + } + } + } +] diff --git a/avm/ptn/network/hub-networking/version.json b/avm/ptn/network/hub-networking/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/network/hub-networking/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/ptn/network/private-link-private-dns-zones/README.md b/avm/ptn/network/private-link-private-dns-zones/README.md index df3015ee11..e5f3e732ba 100644 --- a/avm/ptn/network/private-link-private-dns-zones/README.md +++ b/avm/ptn/network/private-link-private-dns-zones/README.md @@ -63,7 +63,7 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

    -via JSON Parameter file +via JSON parameters file ```json { @@ -76,6 +76,19 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/private-link-private-dns-zones:' + + +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -106,7 +119,7 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

    -via JSON Parameter file +via JSON parameters file ```json { @@ -134,6 +147,26 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/private-link-private-dns-zones:' + +param location = '' +param privateLinkPrivateDnsZones = [ + 'testpdnszone1.int' + 'testpdnszone2.local' +] +param virtualNetworkResourceIdsToLinkTo = [ + '' +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -159,7 +192,7 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

    -via JSON Parameter file +via JSON parameters file ```json { @@ -178,6 +211,21 @@ module privateLinkPrivateDnsZones 'br/public:avm/ptn/network/private-link-privat

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/network/private-link-private-dns-zones:' + +param virtualNetworkResourceIdsToLinkTo = [ + '' +] +``` + +
    +

    + ## Parameters **Optional parameters** diff --git a/avm/ptn/policy-insights/remediation/README.md b/avm/ptn/policy-insights/remediation/README.md index 34c3caff84..ed8b03e57f 100644 --- a/avm/ptn/policy-insights/remediation/README.md +++ b/avm/ptn/policy-insights/remediation/README.md @@ -59,7 +59,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,24 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirmgmin001' +param policyAssignmentId = '' +// Non-required parameters +param location = '' +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +``` + +
    +

    + ### Example 2: _Policy Remediation (Management Group scope)_ This module runs a Policy remediation task at Management Group scope using common parameters. @@ -119,7 +137,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -159,6 +177,28 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirmgmax001' +param policyAssignmentId = '' +// Non-required parameters +param failureThresholdPercentage = '0.5' +param filtersLocations = [] +param location = '' +param parallelDeployments = 1 +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceCount = 10 +``` + +
    +

    + ### Example 3: _Policy Remediation (Resource Group scope)_ This module runs a Policy remediation task at Resource Group scope using minimal parameters. @@ -189,7 +229,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -223,6 +263,26 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirrgmin001' +param policyAssignmentId = '' +// Non-required parameters +param location = '' +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
    +

    + ### Example 4: _Policy Remediation (Resource Group scope)_ This module runs a Policy remediation task at Resource Group scope using common parameters. @@ -258,7 +318,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -307,6 +367,31 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirrgmax001' +param policyAssignmentId = '' +// Non-required parameters +param failureThresholdPercentage = '0.5' +param filtersLocations = [] +param location = '' +param parallelDeployments = 1 +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceCount = 10 +param resourceDiscoveryMode = 'ReEvaluateCompliance' +param resourceGroupName = '' +param subscriptionId = '' +``` + +
    +

    + ### Example 5: _Policy Remediation (Subscription scope)_ This module runs a Policy remediation task at subscription scope using minimal parameters. @@ -336,7 +421,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -367,6 +452,25 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirsubmin001' +param policyAssignmentId = '' +// Non-required parameters +param location = '' +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param subscriptionId = '' +``` + +
    +

    + ### Example 6: _Policy Remediation (Subscription scope)_ This module runs a Policy remediation task at subscription scope using common parameters. @@ -401,7 +505,7 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -447,6 +551,30 @@ module remediation 'br/public:avm/ptn/policy-insights/remediation:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/policy-insights/remediation:' + +// Required parameters +param name = 'pirsubmax001' +param policyAssignmentId = '' +// Non-required parameters +param failureThresholdPercentage = '0.5' +param filtersLocations = [] +param location = '' +param parallelDeployments = 1 +param policyDefinitionReferenceId = 'Prerequisite_DeployExtensionWindows' +param resourceCount = 10 +param resourceDiscoveryMode = 'ReEvaluateCompliance' +param subscriptionId = '' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/ptn/security/security-center/README.md b/avm/ptn/security/security-center/README.md index ccd4a5c3eb..d537c3c74f 100644 --- a/avm/ptn/security/security-center/README.md +++ b/avm/ptn/security/security-center/README.md @@ -60,7 +60,7 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -85,6 +85,23 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/security/security-center:' + +// Required parameters +param scope = '' +param workspaceResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using default parameter set_ This instance deploys the module with default parameters. @@ -120,7 +137,7 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -159,6 +176,31 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/security/security-center:' + +// Required parameters +param scope = '' +param workspaceResourceId = '' +// Non-required parameters +param deviceSecurityGroupProperties = {} +param ioTSecuritySolutionProperties = {} +param location = '' +param securityContactProperties = { + alertNotifications: 'Off' + alertsToAdmins: 'Off' + email: 'foo@contoso.com' + phone: '+12345678' +} +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -186,7 +228,7 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -211,6 +253,23 @@ module securityCenter 'br/public:avm/ptn/security/security-center:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/security/security-center:' + +// Required parameters +param scope = '' +param workspaceResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/README.md b/avm/ptn/virtual-machine-images/azure-image-builder/README.md new file mode 100644 index 0000000000..0ddfb123e2 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/README.md @@ -0,0 +1,1419 @@ +# Custom Images using Azure Image Builder `[VirtualMachineImages/AzureImageBuilder]` + +This module provides you with a packaged solution to create custom images using the Azure Image Builder service publishing to an Azure Compute Gallery. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [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.Compute/galleries` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries) | +| `Microsoft.Compute/galleries/applications` | [2022-03-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-03-03/galleries/applications) | +| `Microsoft.Compute/galleries/images` | [2023-07-03](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-03/galleries/images) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.ManagedIdentity/userAssignedIdentities` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities) | +| `Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities/federatedIdentityCredentials) | +| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | +| `Microsoft.Network/virtualNetworks` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks) | +| `Microsoft.Network/virtualNetworks/subnets` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/subnets) | +| `Microsoft.Network/virtualNetworks/virtualNetworkPeerings` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/virtualNetworks/virtualNetworkPeerings) | +| `Microsoft.Resources/deploymentScripts` | [2023-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2023-08-01/deploymentScripts) | +| `Microsoft.Resources/resourceGroups` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Resources/2024-03-01/resourceGroups) | +| `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | +| `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | +| `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | +| `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | +| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2023-07-01/imageTemplates) | + +## 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/ptn/virtual-machine-images/azure-image-builder:`. + +- [Using small parameter set](#example-1-using-small-parameter-set) +- [Deploying all resources](#example-2-deploying-all-resources) +- [Deploying only the assets & image](#example-3-deploying-only-the-assets-image) +- [Deploying only the base services](#example-4-deploying-only-the-base-services) +- [Deploying only the image](#example-5-deploying-only-the-image) + +### Example 1: _Using small parameter set_ + +This instance deploys the module with min features enabled. + + +

    + +via Bicep module + +```bicep +module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' = { + name: 'azureImageBuilderDeployment' + params: { + // Required parameters + computeGalleryImageDefinitionName: '' + computeGalleryImageDefinitions: [ + { + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + name: 'sid-linux' + osState: 'Generalized' + osType: 'Linux' + } + ] + computeGalleryName: 'galapvmiaibmin' + imageTemplateImageSource: { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' + } + // Non-required parameters + assetsStorageAccountName: 'stapvmiaibmin' + deploymentsToPerform: '' + location: '' + resourceGroupName: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "computeGalleryImageDefinitionName": { + "value": "" + }, + "computeGalleryImageDefinitions": { + "value": [ + { + "hyperVGeneration": "V2", + "identifier": { + "offer": "devops_linux", + "publisher": "devops", + "sku": "devops_linux_az" + }, + "name": "sid-linux", + "osState": "Generalized", + "osType": "Linux" + } + ] + }, + "computeGalleryName": { + "value": "galapvmiaibmin" + }, + "imageTemplateImageSource": { + "value": { + "offer": "ubuntu-24_04-lts", + "publisher": "canonical", + "sku": "server", + "type": "PlatformImage", + "version": "latest" + } + }, + // Non-required parameters + "assetsStorageAccountName": { + "value": "stapvmiaibmin" + }, + "deploymentsToPerform": { + "value": "" + }, + "location": { + "value": "" + }, + "resourceGroupName": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = [ + { + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + name: 'sid-linux' + osState: 'Generalized' + osType: 'Linux' + } +] +param computeGalleryName = 'galapvmiaibmin' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountName = 'stapvmiaibmin' +param deploymentsToPerform = '' +param location = '' +param resourceGroupName = '' +``` + +
    +

    + +### Example 2: _Deploying all resources_ + +This instance deploys the module with the conditions set up to deploy all resource and build the image. + + +

    + +via Bicep module + +```bicep +module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' = { + name: 'azureImageBuilderDeployment' + params: { + // Required parameters + computeGalleryImageDefinitionName: '' + computeGalleryImageDefinitions: [ + { + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + name: '' + osState: 'Generalized' + osType: 'Linux' + } + ] + computeGalleryName: 'galapvmiaiba' + imageTemplateImageSource: { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'canonical' + sku: '22_04-lts-gen2' + type: 'PlatformImage' + version: 'latest' + } + // Non-required parameters + assetsStorageAccountContainerName: '' + assetsStorageAccountName: '' + deploymentsToPerform: '' + imageTemplateCustomizationSteps: [ + { + name: 'PowerShell installation' + scriptUri: '' + type: 'Shell' + } + { + destination: '' + name: '' + sourceUri: '' + type: 'File' + } + { + inline: [ + 'pwsh \'\'' + ] + name: 'Software installation' + type: 'Shell' + } + ] + location: '' + resourceGroupName: '' + storageAccountFilesToUpload: [ + { + name: '' + value: '' + } + { + name: '' + value: '' + } + ] + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "computeGalleryImageDefinitionName": { + "value": "" + }, + "computeGalleryImageDefinitions": { + "value": [ + { + "hyperVGeneration": "V2", + "identifier": { + "offer": "devops_linux", + "publisher": "devops", + "sku": "devops_linux_az" + }, + "name": "", + "osState": "Generalized", + "osType": "Linux" + } + ] + }, + "computeGalleryName": { + "value": "galapvmiaiba" + }, + "imageTemplateImageSource": { + "value": { + "offer": "0001-com-ubuntu-server-jammy", + "publisher": "canonical", + "sku": "22_04-lts-gen2", + "type": "PlatformImage", + "version": "latest" + } + }, + // Non-required parameters + "assetsStorageAccountContainerName": { + "value": "" + }, + "assetsStorageAccountName": { + "value": "" + }, + "deploymentsToPerform": { + "value": "" + }, + "imageTemplateCustomizationSteps": { + "value": [ + { + "name": "PowerShell installation", + "scriptUri": "", + "type": "Shell" + }, + { + "destination": "", + "name": "", + "sourceUri": "", + "type": "File" + }, + { + "inline": [ + "pwsh \"\"" + ], + "name": "Software installation", + "type": "Shell" + } + ] + }, + "location": { + "value": "" + }, + "resourceGroupName": { + "value": "" + }, + "storageAccountFilesToUpload": { + "value": [ + { + "name": "", + "value": "" + }, + { + "name": "", + "value": "" + } + ] + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = [ + { + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + name: '' + osState: 'Generalized' + osType: 'Linux' + } +] +param computeGalleryName = 'galapvmiaiba' +param imageTemplateImageSource = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'canonical' + sku: '22_04-lts-gen2' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountContainerName = '' +param assetsStorageAccountName = '' +param deploymentsToPerform = '' +param imageTemplateCustomizationSteps = [ + { + name: 'PowerShell installation' + scriptUri: '' + type: 'Shell' + } + { + destination: '' + name: '' + sourceUri: '' + type: 'File' + } + { + inline: [ + 'pwsh \'\'' + ] + name: 'Software installation' + type: 'Shell' + } +] +param location = '' +param resourceGroupName = '' +param storageAccountFilesToUpload = [ + { + name: '' + value: '' + } + { + name: '' + value: '' + } +] +``` + +
    +

    + +### Example 3: _Deploying only the assets & image_ + +This instance deploys the module with the conditions set up to only update the assets on the assets storage account and build the image, assuming all dependencies are setup. + + +

    + +via Bicep module + +```bicep +module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' = { + name: 'azureImageBuilderDeployment' + params: { + // Required parameters + computeGalleryImageDefinitionName: '' + computeGalleryImageDefinitions: '' + computeGalleryName: '' + imageTemplateImageSource: { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' + } + // Non-required parameters + assetsStorageAccountContainerName: '' + assetsStorageAccountName: '' + deploymentScriptManagedIdentityName: '' + deploymentScriptStorageAccountName: '' + deploymentScriptSubnetName: '' + deploymentsToPerform: 'Only assets & image' + imageManagedIdentityName: '' + imageSubnetName: '' + imageTemplateCustomizationSteps: [ + { + name: 'Example script' + scriptUri: '' + type: 'Shell' + } + ] + imageTemplateResourceGroupName: '' + location: '' + resourceGroupName: '' + storageAccountFilesToUpload: [ + { + name: '' + value: '' + } + ] + virtualNetworkName: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "computeGalleryImageDefinitionName": { + "value": "" + }, + "computeGalleryImageDefinitions": { + "value": "" + }, + "computeGalleryName": { + "value": "" + }, + "imageTemplateImageSource": { + "value": { + "offer": "ubuntu-24_04-lts", + "publisher": "canonical", + "sku": "server", + "type": "PlatformImage", + "version": "latest" + } + }, + // Non-required parameters + "assetsStorageAccountContainerName": { + "value": "" + }, + "assetsStorageAccountName": { + "value": "" + }, + "deploymentScriptManagedIdentityName": { + "value": "" + }, + "deploymentScriptStorageAccountName": { + "value": "" + }, + "deploymentScriptSubnetName": { + "value": "" + }, + "deploymentsToPerform": { + "value": "Only assets & image" + }, + "imageManagedIdentityName": { + "value": "" + }, + "imageSubnetName": { + "value": "" + }, + "imageTemplateCustomizationSteps": { + "value": [ + { + "name": "Example script", + "scriptUri": "", + "type": "Shell" + } + ] + }, + "imageTemplateResourceGroupName": { + "value": "" + }, + "location": { + "value": "" + }, + "resourceGroupName": { + "value": "" + }, + "storageAccountFilesToUpload": { + "value": [ + { + "name": "", + "value": "" + } + ] + }, + "virtualNetworkName": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = '' +param computeGalleryName = '' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountContainerName = '' +param assetsStorageAccountName = '' +param deploymentScriptManagedIdentityName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptSubnetName = '' +param deploymentsToPerform = 'Only assets & image' +param imageManagedIdentityName = '' +param imageSubnetName = '' +param imageTemplateCustomizationSteps = [ + { + name: 'Example script' + scriptUri: '' + type: 'Shell' + } +] +param imageTemplateResourceGroupName = '' +param location = '' +param resourceGroupName = '' +param storageAccountFilesToUpload = [ + { + name: '' + value: '' + } +] +param virtualNetworkName = '' +``` + +
    +

    + +### Example 4: _Deploying only the base services_ + +This instance deploys the module with the conditions set up to only deploy the base resources, that is everything but the image. + + +

    + +via Bicep module + +```bicep +module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' = { + name: 'azureImageBuilderDeployment' + params: { + // Required parameters + computeGalleryImageDefinitionName: '' + computeGalleryImageDefinitions: [ + { + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + name: '' + osState: 'Generalized' + osType: 'Linux' + } + ] + computeGalleryName: 'galapvmiaibob' + imageTemplateImageSource: { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' + } + // Non-required parameters + assetsStorageAccountName: 'stapvmiaibob' + deploymentsToPerform: 'Only base' + imageManagedIdentityName: 'msi-it-apvmiaibob' + location: '' + resourceGroupName: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "computeGalleryImageDefinitionName": { + "value": "" + }, + "computeGalleryImageDefinitions": { + "value": [ + { + "hyperVGeneration": "V2", + "identifier": { + "offer": "devops_linux", + "publisher": "devops", + "sku": "devops_linux_az" + }, + "name": "", + "osState": "Generalized", + "osType": "Linux" + } + ] + }, + "computeGalleryName": { + "value": "galapvmiaibob" + }, + "imageTemplateImageSource": { + "value": { + "offer": "ubuntu-24_04-lts", + "publisher": "canonical", + "sku": "server", + "type": "PlatformImage", + "version": "latest" + } + }, + // Non-required parameters + "assetsStorageAccountName": { + "value": "stapvmiaibob" + }, + "deploymentsToPerform": { + "value": "Only base" + }, + "imageManagedIdentityName": { + "value": "msi-it-apvmiaibob" + }, + "location": { + "value": "" + }, + "resourceGroupName": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = [ + { + hyperVGeneration: 'V2' + identifier: { + offer: 'devops_linux' + publisher: 'devops' + sku: 'devops_linux_az' + } + name: '' + osState: 'Generalized' + osType: 'Linux' + } +] +param computeGalleryName = 'galapvmiaibob' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param assetsStorageAccountName = 'stapvmiaibob' +param deploymentsToPerform = 'Only base' +param imageManagedIdentityName = 'msi-it-apvmiaibob' +param location = '' +param resourceGroupName = '' +``` + +
    +

    + +### Example 5: _Deploying only the image_ + +This instance deploys the module with the conditions set up to only deploy and bake the image, assuming all dependencies are setup. + + +

    + +via Bicep module + +```bicep +module azureImageBuilder 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' = { + name: 'azureImageBuilderDeployment' + params: { + // Required parameters + computeGalleryImageDefinitionName: '' + computeGalleryImageDefinitions: '' + computeGalleryName: '' + imageTemplateImageSource: { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' + } + // Non-required parameters + deploymentScriptManagedIdentityName: '' + deploymentScriptStorageAccountName: '' + deploymentScriptSubnetName: '' + deploymentsToPerform: 'Only image' + imageManagedIdentityName: '' + imageSubnetName: '' + imageTemplateCustomizationSteps: [ + { + name: 'Example script' + scriptUri: '' + type: 'Shell' + } + ] + imageTemplateResourceGroupName: '' + location: '' + resourceGroupName: '' + virtualNetworkName: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "computeGalleryImageDefinitionName": { + "value": "" + }, + "computeGalleryImageDefinitions": { + "value": "" + }, + "computeGalleryName": { + "value": "" + }, + "imageTemplateImageSource": { + "value": { + "offer": "ubuntu-24_04-lts", + "publisher": "canonical", + "sku": "server", + "type": "PlatformImage", + "version": "latest" + } + }, + // Non-required parameters + "deploymentScriptManagedIdentityName": { + "value": "" + }, + "deploymentScriptStorageAccountName": { + "value": "" + }, + "deploymentScriptSubnetName": { + "value": "" + }, + "deploymentsToPerform": { + "value": "Only image" + }, + "imageManagedIdentityName": { + "value": "" + }, + "imageSubnetName": { + "value": "" + }, + "imageTemplateCustomizationSteps": { + "value": [ + { + "name": "Example script", + "scriptUri": "", + "type": "Shell" + } + ] + }, + "imageTemplateResourceGroupName": { + "value": "" + }, + "location": { + "value": "" + }, + "resourceGroupName": { + "value": "" + }, + "virtualNetworkName": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/virtual-machine-images/azure-image-builder:' + +// Required parameters +param computeGalleryImageDefinitionName = '' +param computeGalleryImageDefinitions = '' +param computeGalleryName = '' +param imageTemplateImageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +// Non-required parameters +param deploymentScriptManagedIdentityName = '' +param deploymentScriptStorageAccountName = '' +param deploymentScriptSubnetName = '' +param deploymentsToPerform = 'Only image' +param imageManagedIdentityName = '' +param imageSubnetName = '' +param imageTemplateCustomizationSteps = [ + { + name: 'Example script' + scriptUri: '' + type: 'Shell' + } +] +param imageTemplateResourceGroupName = '' +param location = '' +param resourceGroupName = '' +param virtualNetworkName = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`computeGalleryImageDefinitionName`](#parameter-computegalleryimagedefinitionname) | string | The name of Image Definition of the Azure Compute Gallery to host the new image version. | +| [`computeGalleryImageDefinitions`](#parameter-computegalleryimagedefinitions) | array | The Image Definitions in the Azure Compute Gallery. | +| [`computeGalleryName`](#parameter-computegalleryname) | string | The name of the Azure Compute Gallery. | +| [`imageTemplateImageSource`](#parameter-imagetemplateimagesource) | object | The image source to use for the Image Template. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`assetsStorageAccountContainerName`](#parameter-assetsstorageaccountcontainername) | string | The name of container in the Storage Account. | +| [`assetsStorageAccountName`](#parameter-assetsstorageaccountname) | string | The name of the storage account. Only needed if you want to upload scripts to be used during image baking. | +| [`deploymentScriptManagedIdentityName`](#parameter-deploymentscriptmanagedidentityname) | string | The name of the Managed Identity used by deployment scripts. | +| [`deploymentScriptStorageAccountName`](#parameter-deploymentscriptstorageaccountname) | string | The name of the storage account. | +| [`deploymentScriptSubnetName`](#parameter-deploymentscriptsubnetname) | string | The name of the Image Template Virtual Network Subnet to create. | +| [`deploymentsToPerform`](#parameter-deploymentstoperform) | string | A parameter to control which deployments should be executed. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`imageManagedIdentityName`](#parameter-imagemanagedidentityname) | string | The name of the Managed Identity used by the Azure Image Builder. | +| [`imageSubnetName`](#parameter-imagesubnetname) | string | The name of the Image Template Virtual Network Subnet to create. | +| [`imageTemplateCustomizationSteps`](#parameter-imagetemplatecustomizationsteps) | array | The customization steps to use for the Image Template. | +| [`imageTemplateDeploymentScriptName`](#parameter-imagetemplatedeploymentscriptname) | string | The name of the Deployment Script to trigger the image template baking. | +| [`imageTemplateName`](#parameter-imagetemplatename) | string | The name of the Image Template. | +| [`imageTemplateResourceGroupName`](#parameter-imagetemplateresourcegroupname) | string | The name of the Resource Group to deploy the Image Template resources into. | +| [`location`](#parameter-location) | string | The location to deploy into. | +| [`resourceGroupName`](#parameter-resourcegroupname) | string | The name of the Resource Group. | +| [`storageAccountFilesToUpload`](#parameter-storageaccountfilestoupload) | array | The files to upload to the Assets Storage Account. | +| [`storageDeploymentScriptName`](#parameter-storagedeploymentscriptname) | string | The name of the Deployment Script to upload files to the assets storage account. | +| [`virtualNetworkAddressPrefix`](#parameter-virtualnetworkaddressprefix) | string | The address space of the Virtual Network. | +| [`virtualNetworkDeploymentScriptSubnetAddressPrefix`](#parameter-virtualnetworkdeploymentscriptsubnetaddressprefix) | string | The address space of the Virtual Network Subnet used by the deployment script. | +| [`virtualNetworkName`](#parameter-virtualnetworkname) | string | The name of the Virtual Network. | +| [`virtualNetworkSubnetAddressPrefix`](#parameter-virtualnetworksubnetaddressprefix) | string | The address space of the Virtual Network Subnet. | +| [`waitDeploymentScriptName`](#parameter-waitdeploymentscriptname) | string | The name of the Deployment Script to wait for for the image baking to conclude. | +| [`waitForImageBuild`](#parameter-waitforimagebuild) | bool | A parameter to control if the deployment should wait for the image build to complete. | +| [`waitForImageBuildTimeout`](#parameter-waitforimagebuildtimeout) | string | A parameter to control the timeout of the deployment script waiting for the image build. | + +**Generated parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`baseTime`](#parameter-basetime) | string | Do not provide a value! This date value is used to generate a SAS token to access the modules. | + +### Parameter: `computeGalleryImageDefinitionName` + +The name of Image Definition of the Azure Compute Gallery to host the new image version. + +- Required: Yes +- Type: string + +### Parameter: `computeGalleryImageDefinitions` + +The Image Definitions in the Azure Compute Gallery. + +- Required: Yes +- Type: array + +### Parameter: `computeGalleryName` + +The name of the Azure Compute Gallery. + +- Required: Yes +- Type: string + +### Parameter: `imageTemplateImageSource` + +The image source to use for the Image Template. + +- Required: Yes +- Type: object + +### Parameter: `assetsStorageAccountContainerName` + +The name of container in the Storage Account. + +- Required: No +- Type: string +- Default: `'aibscripts'` + +### Parameter: `assetsStorageAccountName` + +The name of the storage account. Only needed if you want to upload scripts to be used during image baking. + +- Required: No +- Type: string + +### Parameter: `deploymentScriptManagedIdentityName` + +The name of the Managed Identity used by deployment scripts. + +- Required: No +- Type: string +- Default: `'msi-ds'` + +### Parameter: `deploymentScriptStorageAccountName` + +The name of the storage account. + +- Required: No +- Type: string +- Default: `[format('{0}ds', parameters('assetsStorageAccountName'))]` + +### Parameter: `deploymentScriptSubnetName` + +The name of the Image Template Virtual Network Subnet to create. + +- Required: No +- Type: string +- Default: `'subnet-ds'` + +### Parameter: `deploymentsToPerform` + +A parameter to control which deployments should be executed. + +- Required: No +- Type: string +- Default: `'Only assets & image'` +- Allowed: + ```Bicep + [ + 'All' + 'Only assets & image' + 'Only base' + 'Only image' + ] + ``` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `imageManagedIdentityName` + +The name of the Managed Identity used by the Azure Image Builder. + +- Required: No +- Type: string +- Default: `'msi-aib'` + +### Parameter: `imageSubnetName` + +The name of the Image Template Virtual Network Subnet to create. + +- Required: No +- Type: string +- Default: `'subnet-it'` + +### Parameter: `imageTemplateCustomizationSteps` + +The customization steps to use for the Image Template. + +- Required: No +- Type: array + +### Parameter: `imageTemplateDeploymentScriptName` + +The name of the Deployment Script to trigger the image template baking. + +- Required: No +- Type: string +- Default: `'ds-triggerBuild-imageTemplate'` + +### Parameter: `imageTemplateName` + +The name of the Image Template. + +- Required: No +- Type: string +- Default: `'it-aib'` + +### Parameter: `imageTemplateResourceGroupName` + +The name of the Resource Group to deploy the Image Template resources into. + +- Required: No +- Type: string +- Default: `[format('{0}-image-build', parameters('resourceGroupName'))]` + +### Parameter: `location` + +The location to deploy into. + +- Required: No +- Type: string +- Default: `[deployment().location]` + +### Parameter: `resourceGroupName` + +The name of the Resource Group. + +- Required: No +- Type: string +- Default: `'rg-ado-agents'` + +### Parameter: `storageAccountFilesToUpload` + +The files to upload to the Assets Storage Account. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-storageaccountfilestouploadname) | string | The name of the environment variable. | +| [`secureValue`](#parameter-storageaccountfilestouploadsecurevalue) | securestring | The value of the secure environment variable. | +| [`value`](#parameter-storageaccountfilestouploadvalue) | string | The value of the environment variable. | + +### Parameter: `storageAccountFilesToUpload.name` + +The name of the environment variable. + +- Required: Yes +- Type: string + +### Parameter: `storageAccountFilesToUpload.secureValue` + +The value of the secure environment variable. + +- Required: No +- Type: securestring + +### Parameter: `storageAccountFilesToUpload.value` + +The value of the environment variable. + +- Required: No +- Type: string + +### Parameter: `storageDeploymentScriptName` + +The name of the Deployment Script to upload files to the assets storage account. + +- Required: No +- Type: string +- Default: `'ds-triggerUpload-storage'` + +### Parameter: `virtualNetworkAddressPrefix` + +The address space of the Virtual Network. + +- Required: No +- Type: string +- Default: `'10.0.0.0/16'` + +### Parameter: `virtualNetworkDeploymentScriptSubnetAddressPrefix` + +The address space of the Virtual Network Subnet used by the deployment script. + +- Required: No +- Type: string +- Default: `[cidrSubnet(parameters('virtualNetworkAddressPrefix'), 24, 1)]` + +### Parameter: `virtualNetworkName` + +The name of the Virtual Network. + +- Required: No +- Type: string +- Default: `'vnet-it'` + +### Parameter: `virtualNetworkSubnetAddressPrefix` + +The address space of the Virtual Network Subnet. + +- Required: No +- Type: string +- Default: `[cidrSubnet(parameters('virtualNetworkAddressPrefix'), 24, 0)]` + +### Parameter: `waitDeploymentScriptName` + +The name of the Deployment Script to wait for for the image baking to conclude. + +- Required: No +- Type: string +- Default: `'ds-wait-imageTemplate-build'` + +### Parameter: `waitForImageBuild` + +A parameter to control if the deployment should wait for the image build to complete. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `waitForImageBuildTimeout` + +A parameter to control the timeout of the deployment script waiting for the image build. + +- Required: No +- Type: string +- Default: `'PT1H'` + +### Parameter: `baseTime` + +Do not provide a value! This date value is used to generate a SAS token to access the modules. + +- Required: No +- Type: string +- Default: `[utcNow()]` + +## Outputs + +_None_ + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/compute/gallery:0.7.0` | Remote reference | +| `br/public:avm/res/managed-identity/user-assigned-identity:0.4.0` | Remote reference | +| `br/public:avm/res/network/virtual-network:0.4.0` | Remote reference | +| `br/public:avm/res/resources/deployment-script:0.4.0` | Remote reference | +| `br/public:avm/res/storage/storage-account:0.9.1` | Remote reference | +| `br/public:avm/res/virtual-machine-images/image-template:0.4.0` | Remote reference | + +## Notes + + +### Prerequisites + +The deployments described in the following sections assume certain prerequisites to be in place prior to deployment. + +- The deployment principal (e.g., the Service Principal tied to the deploying Service Connection) must have at least `Contributor` & `User Access Adminitrator` permissions on the target subscription to be able to deploy both resources and assign permissions to created user-assigned identities +- If you have a policy in place that prevents Storage Accounts from being deployed without a Firewall, you have to create an exemption for the Image Template / Staging Resource Group you can configure for the Image Template Resource (parameter `imageTemplateResourceGroupName`). The rationale is that the Azure-Image-Builder service uses this resource group to deploy both temporal resources used during the image build (e.g., a Virtual Machine), as well as a Storage Account to store temporal files & a 'packerlogs/customization.log' file in (which contains the logs of the image build). This Storage Account has no firewall configured, has a random name, and cannot be configured at deploy time. + +### Elements +The image creation uses several components: + +|     | Resource | Description | +|--|--|--| +| ResourceGroup | Resource Group | The resource group hosting the image resources | +| ResourceGroup | (Image) Resource Group | The resource group hosting the resources created during the image build | +| Storage Account | (Assets) Storage Account | The storage account that hosts the image customization scripts used by the _Azure Image Building_ when executing the image template. | +| Storage Account | (DS) Storage Account | The storage account that hosts the files of the Deployment Scripts. Required for private networking. | +| Managed Identity | (Image) User-Assigned Managed Identity | Azure Active Directory feature that eliminates the need for credentials in code, rotates credentials automatically, and reduces identity maintenance. In the context of the imaging construct, the managed identity (MSI) is used by the Image Builder Service. It is assigned contributor permissions on the subscription to be able to bake the image. Further, it is assigned read permissions on the Assets Storage Account Container in order to consume the customization scripts. | +| Managed Identity | (DS) User-Assigned Managed Identity | Azure Active Directory feature that eliminates the need for credentials in code, rotates credentials automatically, and reduces identity maintenance. In the context of the imaging construct, the managed identity (MSI) is used by the Image Builder Service. It's assigned permissions on the Image Template to trigger it, the Deployment Script Storage Account for Private Networking, and the Assets Storage Account to upload files. | +| Managed Identity | (Storage) Deployment Script | The Deployment Script that uploads the customization scripts to the Assets Storage Account. | +| Managed Identity | (Trigger) Deployment Script | The Deployment Script that triggers the Image Template build. | +| Azure Compute Gallery | Azure Compute Gallery | Azure service that helps to build structure and organization for managed images. Provides global replication, versioning, grouping, sharing across subscriptions and scaling. The plain resource in itself is like an empty container. | +| Azure Compute Gallery Image | Azure Compute Gallery Image | Created within a gallery and contains information about the image and requirements for using it internally. This includes metadata like whether the image is Windows or Linux, release notes and recommended compute resources. Like the image gallery itself it acts like a container for the actual images. | +| Image Template | Image Template | A standard Azure Image Builder template that defines the parameters for building a custom image with AIB. The parameters include image source (Marketplace, custom image, etc.), customization options (i.e., Updates, scripts, restarts), and distribution (i.e., managed image, Azure Compute Gallery). The template is not an actual resource. Instead, when an image template is created, Azure stores all the metadata of the referenced Azure Compute Gallery Image alongside other image backing instructions as a hidden resource in a temporary resource group. | +| Image Version | Image Version | An image version (for example `0.24322.55884`) is what you use to create a VM when using a gallery. You can have multiple versions of an image as needed for your environment. This value **cannot** be chosen. | + +

    + +Run workflow + +### First deployment +When triggering the deployment for the first time, make sure you either select `All` or `Only base` for the `deploymentsToPerform` parameter. In either case the template will deploy all resources and scripts you will subsequently need to create the images. For any subsequent run, you can go with any option you need. + +The steps the _Azure Image Builder_ performs on the image are defined by elements configured in the `customizationSteps` parameter of the image template parameter file. In our setup we [Usage Examples](#usage-examples) we use one or multiple custom scripts that are uploaded by the template to a storage account ahead of the image deployment. + +### Mermaid Graphs + +The following graphs show which services are created based on the chosen `deploymentsToPerform`. As such, they show a (simplified) view of the order and relations in between the included deployments. + +#### (Simplified) All +```mermaid + graph TD; + imageTemplateRg --> imageTemplate + rg --> vnet + rg --> dsMsi + rg --> imageMSI + rg --> azureComputeGallery + + azureComputeGallery --> imageTemplate + + imageMSI --> imageMSI_rbac + + dsMsi --> assetsStorageAccount + imageMSI --> assetsStorageAccount + + dsMsi --> dsStorageAccount + vnet --> dsStorageAccount + + dsStorageAccount --> storageAccount_upload + assetsStorageAccount --> storageAccount_upload + dsMsi --> imageTemplate + storageAccount_upload ==> imageTemplate + + imageTemplate --> imageTemplate_trigger + + imageTemplate_trigger ==> imageTemplate_wait + imageMSI_rbac ==> imageTemplate +``` + + + +#### (Simplified) Only base +```mermaid + graph TD; + rg -- provides value to --> azureComputeGallery + rg -- provides value to --> vnet + rg -- provides value to --> dsMsi + rg -- provides value to --> imageMSI + + imageTemplateRg + + vnet -- provides value to --> dsStorageAccount + + dsMsi -- provides value to --> dsStorageAccount + dsStorageAccount -- provides value to --> storageAccount_upload + assetsStorageAccount -- provides value to --> storageAccount_upload + + dsMsi -- provides value to --> assetsStorageAccount + imageMSI -- provides value to --> assetsStorageAccount + imageMSI -- provides value to --> imageMSI_rbac +``` + +#### Only assets & image +Assumes all other services + permissions are deployed +```mermaid + graph TD; + imageTemplateRg -- provides value to --> imageTemplate + storageAccount_upload -- must come after --> imageTemplate + imageTemplate -- provides value to --> imageTemplate_trigger + imageTemplate -- provides value to --> imageTemplate_wait + imageTemplate_trigger -- must come after --> imageTemplate_wait +``` + +#### Only image +Assumes all other services + permissions are deployed +```mermaid + graph TD; + imageTemplateRg -- provides value to --> imageTemplate + imageTemplate -- provides value to --> imageTemplate_trigger + imageTemplate -- provides value to --> imageTemplate_wait + imageTemplate_trigger -- must come after --> imageTemplate_wait +``` + +### Troubleshooting + +Most commonly issues with the construct occur during the image building process due to script errors. As those are hard to troubleshoot and the AIB VMs that are used to bake images are not accessible, the AIB service writes logs into a storage account in the 'staging' resource group it generates during the building process as documented [here](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/image-builder-troubleshoot#customization-log). + +Aside from the packer logs, it will also contain the logs generated by the provided customization scripts and hence provide you insights into 'where' something wrong, and ideally also 'what' went wrong. + +## 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/ptn/virtual-machine-images/azure-image-builder/main.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/main.bicep new file mode 100644 index 0000000000..34d5a6048e --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/main.bicep @@ -0,0 +1,606 @@ +targetScope = 'subscription' + +metadata name = 'Custom Images using Azure Image Builder' +metadata description = 'This module provides you with a packaged solution to create custom images using the Azure Image Builder service publishing to an Azure Compute Gallery.' +metadata owner = 'AlexanderSehr' + +// ================ // +// Input Parameters // +// ================ // + +@description('Optional. A parameter to control which deployments should be executed.') +@allowed([ + 'All' + 'Only base' + 'Only assets & image' + 'Only image' +]) +param deploymentsToPerform string = 'Only assets & image' + +// Resource Group Parameters +@description('Optional. The name of the Resource Group.') +param resourceGroupName string = 'rg-ado-agents' + +@description('Optional. The name of the Resource Group to deploy the Image Template resources into.') +param imageTemplateResourceGroupName string = '${resourceGroupName}-image-build' + +// User Assigned Identity (MSI) Parameters +@description('Optional. The name of the Managed Identity used by deployment scripts.') +param deploymentScriptManagedIdentityName string = 'msi-ds' + +@description('Optional. The name of the Managed Identity used by the Azure Image Builder.') +param imageManagedIdentityName string = 'msi-aib' + +// Azure Compute Gallery Parameters +@description('Required. The name of the Azure Compute Gallery.') +param computeGalleryName string + +@description('Required. The Image Definitions in the Azure Compute Gallery.') +param computeGalleryImageDefinitions array + +// Storage Account Parameters +@description('Optional. The name of the storage account. Only needed if you want to upload scripts to be used during image baking.') +param assetsStorageAccountName string? + +@description('Optional. The name of the storage account.') +param deploymentScriptStorageAccountName string = '${assetsStorageAccountName}ds' + +@description('Optional. The name of container in the Storage Account.') +param assetsStorageAccountContainerName string = 'aibscripts' + +// Virtual Network Parameters +@description('Optional. The name of the Virtual Network.') +param virtualNetworkName string = 'vnet-it' + +@description('Optional. The address space of the Virtual Network.') +param virtualNetworkAddressPrefix string = '10.0.0.0/16' + +@description('Optional. The name of the Image Template Virtual Network Subnet to create.') +param imageSubnetName string = 'subnet-it' + +@description('Optional. The address space of the Virtual Network Subnet.') +param virtualNetworkSubnetAddressPrefix string = cidrSubnet(virtualNetworkAddressPrefix, 24, 0) + +@description('Optional. The name of the Image Template Virtual Network Subnet to create.') +param deploymentScriptSubnetName string = 'subnet-ds' + +@description('Optional. The address space of the Virtual Network Subnet used by the deployment script.') +param virtualNetworkDeploymentScriptSubnetAddressPrefix string = cidrSubnet(virtualNetworkAddressPrefix, 24, 1) + +// Deployment Script Parameters +@description('Optional. The name of the Deployment Script to upload files to the assets storage account.') +param storageDeploymentScriptName string = 'ds-triggerUpload-storage' + +@description('Optional. The files to upload to the Assets Storage Account.') +param storageAccountFilesToUpload storageAccountFilesToUploadType[]? + +@description('Optional. The name of the Deployment Script to trigger the image template baking.') +param imageTemplateDeploymentScriptName string = 'ds-triggerBuild-imageTemplate' + +@description('Optional. The name of the Deployment Script to wait for for the image baking to conclude.') +param waitDeploymentScriptName string = 'ds-wait-imageTemplate-build' + +// Image Template Parameters +@description('Optional. The name of the Image Template.') +param imageTemplateName string = 'it-aib' + +@description('Required. The image source to use for the Image Template.') +param imageTemplateImageSource object + +@description('Optional. The customization steps to use for the Image Template.') +@minLength(1) +param imageTemplateCustomizationSteps array? + +@description('Required. The name of Image Definition of the Azure Compute Gallery to host the new image version.') +param computeGalleryImageDefinitionName string + +@description('Optional. A parameter to control if the deployment should wait for the image build to complete.') +param waitForImageBuild bool = true + +@description('Optional. A parameter to control the timeout of the deployment script waiting for the image build.') +param waitForImageBuildTimeout string = 'PT1H' + +// Shared Parameters +@description('Optional. The location to deploy into.') +param location string = deployment().location + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Generated. Do not provide a value! This date value is used to generate a SAS token to access the modules.') +param baseTime string = utcNow() + +var formattedTime = replace(replace(replace(baseTime, ':', ''), '-', ''), ' ', '') + +// Role required for deployment script to be able to use a storage account via private networking +resource storageFileDataPrivilegedContributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Priveleged Contributor + scope: tenant() +} +resource contributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + scope: tenant() +} + +// =========== // +// Deployments // +// =========== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.vmimages-azureimagebuilder.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + location: location + 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' + } + } + } + } +} + +////////////////////////// +// START: ALL // +// START: ONLY BASE // +// ==================== // + +// Resource Groups +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: resourceGroupName + location: location +} + +// Always deployed as both an infra element & needed as a staging resource group for image building +resource imageTemplateRg 'Microsoft.Resources/resourceGroups@2024-03-01' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: imageTemplateResourceGroupName + location: location +} + +// User Assigned Identity (MSI) +module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: '${deployment().name}-ds-msi' + scope: rg + params: { + name: deploymentScriptManagedIdentityName + location: location + enableTelemetry: enableTelemetry + } +} + +module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: '${deployment().name}-image-msi' + scope: rg + params: { + name: imageManagedIdentityName + location: location + enableTelemetry: enableTelemetry + } +} + +// MSI Subscription contributor assignment +resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: guid( + subscription().id, + '${subscription().id}/resourceGroups/${resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${imageManagedIdentityName}', + contributorRole.id + ) + properties: { + // TODO: Requries conditions. Tracked issue: https://github.com/Azure/bicep/issues/2371 + principalId: (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') + ? imageMSI.outputs.principalId + : '' + roleDefinitionId: contributorRole.id + principalType: 'ServicePrincipal' + } +} + +// Azure Compute Gallery +module azureComputeGallery 'br/public:avm/res/compute/gallery:0.7.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: '${deployment().name}-acg' + scope: rg + params: { + name: computeGalleryName + images: computeGalleryImageDefinitions + location: location + enableTelemetry: enableTelemetry + } +} + +// Image Template Virtual Network +module vnet 'br/public:avm/res/network/virtual-network:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: '${deployment().name}-vnet' + scope: rg + params: { + name: virtualNetworkName + addressPrefixes: [ + virtualNetworkAddressPrefix + ] + subnets: [ + { + name: imageSubnetName + addressPrefix: virtualNetworkSubnetAddressPrefix + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET + serviceEndpoints: [ + 'Microsoft.Storage' + ] + } + { + name: deploymentScriptSubnetName + addressPrefix: virtualNetworkDeploymentScriptSubnetAddressPrefix + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET - temp + serviceEndpoints: [ + 'Microsoft.Storage' + ] + delegation: 'Microsoft.ContainerInstance/containerGroups' + } + ] + location: location + enableTelemetry: enableTelemetry + } +} + +// Assets Storage Account +module assetsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: '${deployment().name}-files-sa' + scope: rg + params: { + name: assetsStorageAccountName! + allowSharedKeyAccess: false // Keys not needed if MSI is granted access + enableTelemetry: enableTelemetry + location: location + networkAcls: { + // NOTE: If Firewall is enabled, it causes the Image Template to not be able to connect to the storage account. It's NOT a permission issue (ref: https://github.com/danielsollondon/azvmimagebuilder/issues/31#issuecomment-1793779854) + defaultAction: 'Allow' + // defaultAction: 'Deny' + // virtualNetworkRules: [ + // { + // // Allow image template to access data + // action: 'Allow' + // id: vnet.outputs.subnetResourceIds[0] // imageSubnet + // } + // { + // // Allow deployment script to access storage account to upload data + // action: 'Allow' + // id: vnet.outputs.subnetResourceIds[1] // deploymentScriptSubnet + // } + // ] + } + blobServices: { + containers: [ + { + name: assetsStorageAccountContainerName + publicAccess: 'None' + roleAssignments: [ + { + // Allow Infra MSI to access storage account container to upload files - DO NOT REMOVE + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') + ? dsMsi.outputs.principalId + : '' // Requires condition als Bicep will otherwise try to resolve the null reference + principalType: 'ServicePrincipal' + } + { + // Allow image MSI to access storage account container to read files - DO NOT REMOVE + roleDefinitionIdOrName: 'Storage Blob Data Reader' // 'Storage Blob Data Reader' + principalId: (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') + ? imageMSI.outputs.principalId + : '' // Requires condition als Bicep will otherwise try to resolve the null reference + principalType: 'ServicePrincipal' + } + ] + } + ] + containerDeleteRetentionPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + } + } +} + +// Deployment scripts & their storage account +module dsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') { + name: '${deployment().name}-ds-sa' + scope: rg + params: { + name: deploymentScriptStorageAccountName + allowSharedKeyAccess: true // May not be disabled to allow deployment script to access storage account files + enableTelemetry: enableTelemetry + roleAssignments: [ + { + // Allow MSI to leverage the storage account for private networking of container instance + // ref: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-bicep#access-private-virtual-network + roleDefinitionIdOrName: storageFileDataPrivilegedContributorRole.id // Storage File Data Priveleged Contributor + principalId: (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base') + ? dsMsi.outputs.principalId + : '' // Requires condition als Bicep will otherwise try to resolve the null reference + principalType: 'ServicePrincipal' + } + ] + location: location + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + // Allow deployment script to use storage account for private networking of container instance + action: 'Allow' + id: resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetworkName, + deploymentScriptSubnetName + ) + } + ] + } + } + dependsOn: [ + vnet + ] +} + +//////////////////////////////////// +// START: ONLY ASSETS & IMAGE // +// ============================== // + +// Upload storage account files +module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only base' || deploymentsToPerform == 'Only assets & image') { + name: '${deployment().name}-storage-upload-ds' + scope: resourceGroup(resourceGroupName) + params: { + name: '${storageDeploymentScriptName}-${formattedTime}' + kind: 'AzurePowerShell' + azPowerShellVersion: '12.0' + enableTelemetry: enableTelemetry + managedIdentities: { + userAssignedResourcesIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.ManagedIdentity/userAssignedIdentities', + deploymentScriptManagedIdentityName + ) + ] + } + scriptContent: loadTextContent('../../../utilities/e2e-template-assets/scripts/Set-StorageContainerContentByEnvVar.ps1') + environmentVariables: map(storageAccountFilesToUpload ?? [], file => { + name: '__SCRIPT__${replace(replace(file.name, '-', '__'), '.', '_') }' // May only be alphanumeric characters & underscores. The upload will replace '_' with '.' and '__' with '-'. E.g., Install__LinuxPowerShell_sh will be Install-LinuxPowerShell.sh + value: file.?value + secureValue: file.?secureValue + }) + arguments: ' -StorageAccountName "${assetsStorageAccountName}" -TargetContainer "${assetsStorageAccountContainerName}"' + timeout: 'PT30M' + cleanupPreference: 'Always' + location: location + storageAccountResourceId: resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Storage/storageAccounts', + deploymentScriptStorageAccountName + ) + subnetResourceIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetworkName, + deploymentScriptSubnetName + ) + ] + } + dependsOn: [ + // Conditionally required + rg + assetsStorageAccount + dsMsi + dsStorageAccount + vnet + ] +} + +// ================== // +// END: ONLY BASE // +//////////////////////// + +/////////////////////////// +// START: ONLY IMAGE // +// ===================== // + +// Image template +resource dsMsi_existing 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { + name: deploymentScriptManagedIdentityName + scope: resourceGroup(resourceGroupName) +} + +module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { + name: '${deployment().name}-it' + scope: resourceGroup(resourceGroupName) + params: { + customizationSteps: imageTemplateCustomizationSteps + imageSource: imageTemplateImageSource + name: imageTemplateName + enableTelemetry: enableTelemetry + managedIdentities: { + userAssignedResourceIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.ManagedIdentity/userAssignedIdentities', + imageManagedIdentityName + ) + ] + } + distributions: [ + { + type: 'SharedImage' + sharedImageGalleryImageDefinitionResourceId: resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Compute/galleries/images', + computeGalleryName, + computeGalleryImageDefinitionName + ) + } + ] + + // subnetResourceId: vnet.outputs.subnetResourceIds[0] // Image Subnet + subnetResourceId: resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetworkName, + imageSubnetName + ) + location: location + stagingResourceGroupResourceId: imageTemplateRg.id + roleAssignments: [ + { + roleDefinitionIdOrName: 'Contributor' + // Allow deployment script to trigger image build. Use 'existing' reference if only part of solution is deployed + principalId: (deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') + ? dsMsi_existing.properties.principalId + : dsMsi.outputs.principalId + principalType: 'ServicePrincipal' + } + ] + } + dependsOn: [ + storageAccount_upload + imageMSI_rbac + rg + imageMSI + azureComputeGallery + vnet + ] +} + +// Deployment script to trigger image build +module imageTemplate_trigger 'br/public:avm/res/resources/deployment-script:0.4.0' = if (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') { + name: '${deployment().name}-imageTemplate-trigger-ds' + scope: resourceGroup(resourceGroupName) + params: { + name: '${imageTemplateDeploymentScriptName}-${formattedTime}-${(deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') ? imageTemplate.outputs.name : ''}' // Requires condition als Bicep will otherwise try to resolve the null reference + kind: 'AzurePowerShell' + azPowerShellVersion: '12.0' + managedIdentities: { + userAssignedResourcesIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.ManagedIdentity/userAssignedIdentities', + deploymentScriptManagedIdentityName + ) + ] + } + enableTelemetry: enableTelemetry + scriptContent: (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image') + ? imageTemplate.outputs.runThisCommand + : '' // Requires condition als Bicep will otherwise try to resolve the null reference + timeout: 'PT30M' + cleanupPreference: 'Always' + location: location + // storageAccountResourceId: dsStorageAccount.outputs.resourceId + storageAccountResourceId: resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Storage/storageAccounts', + deploymentScriptStorageAccountName + ) + subnetResourceIds: [ + // vnet.outputs.subnetResourceIds[1] // deploymentScriptSubnet + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetworkName, + deploymentScriptSubnetName + ) + ] + } + dependsOn: [ + // Always required + imageTemplate + // Conditionally required + rg + dsMsi + dsStorageAccount + storageAccount_upload + vnet + ] +} + +module imageTemplate_wait 'br/public:avm/res/resources/deployment-script:0.4.0' = if (waitForImageBuild && (deploymentsToPerform == 'All' || deploymentsToPerform == 'Only assets & image' || deploymentsToPerform == 'Only image')) { + name: '${deployment().name}-imageTemplate-wait-ds' + scope: resourceGroup(resourceGroupName) + params: { + name: '${waitDeploymentScriptName}-${formattedTime}' + kind: 'AzurePowerShell' + azPowerShellVersion: '12.0' + managedIdentities: { + userAssignedResourcesIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.ManagedIdentity/userAssignedIdentities', + deploymentScriptManagedIdentityName + ) + ] + } + scriptContent: loadTextContent('../../../utilities/e2e-template-assets/scripts/Wait-ForImageBuild.ps1') + arguments: ' -ImageTemplateName "${imageTemplate.outputs.name}" -ResourceGroupName "${resourceGroupName}"' + timeout: waitForImageBuildTimeout + cleanupPreference: 'Always' + location: location + storageAccountResourceId: resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Storage/storageAccounts', + deploymentScriptStorageAccountName + ) + subnetResourceIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.Network/virtualNetworks/subnets', + virtualNetworkName, + deploymentScriptSubnetName + ) + ] + } + dependsOn: [ + imageTemplate_trigger + rg + vnet + dsStorageAccount + dsMsi + ] +} + +// ============================= // +// END: ALL // +// END: ONLY ASSETS & IMAGE // +// END: ONLY IMAGE // +/////////////////////////////////// + +// =============== // +// Definitions // +// =============== // +@export() +type storageAccountFilesToUploadType = { + @description('Required. The name of the environment variable.') + name: string + + @description('Required. The value of the secure environment variable.') + @secure() + secureValue: string? + + @description('Required. The value of the environment variable.') + value: string? +} diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/main.json b/avm/ptn/virtual-machine-images/azure-image-builder/main.json new file mode 100644 index 0000000000..e8e8b71562 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/main.json @@ -0,0 +1,16177 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "4580919221810730076" + }, + "name": "Custom Images using Azure Image Builder", + "description": "This module provides you with a packaged solution to create custom images using the Azure Image Builder service publishing to an Azure Compute Gallery.", + "owner": "AlexanderSehr" + }, + "definitions": { + "storageAccountFilesToUploadType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Required. The value of the secure environment variable." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The value of the environment variable." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "deploymentsToPerform": { + "type": "string", + "defaultValue": "Only assets & image", + "allowedValues": [ + "All", + "Only base", + "Only assets & image", + "Only image" + ], + "metadata": { + "description": "Optional. A parameter to control which deployments should be executed." + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "rg-ado-agents", + "metadata": { + "description": "Optional. The name of the Resource Group." + } + }, + "imageTemplateResourceGroupName": { + "type": "string", + "defaultValue": "[format('{0}-image-build', parameters('resourceGroupName'))]", + "metadata": { + "description": "Optional. The name of the Resource Group to deploy the Image Template resources into." + } + }, + "deploymentScriptManagedIdentityName": { + "type": "string", + "defaultValue": "msi-ds", + "metadata": { + "description": "Optional. The name of the Managed Identity used by deployment scripts." + } + }, + "imageManagedIdentityName": { + "type": "string", + "defaultValue": "msi-aib", + "metadata": { + "description": "Optional. The name of the Managed Identity used by the Azure Image Builder." + } + }, + "computeGalleryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Azure Compute Gallery." + } + }, + "computeGalleryImageDefinitions": { + "type": "array", + "metadata": { + "description": "Required. The Image Definitions in the Azure Compute Gallery." + } + }, + "assetsStorageAccountName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the storage account. Only needed if you want to upload scripts to be used during image baking." + } + }, + "deploymentScriptStorageAccountName": { + "type": "string", + "defaultValue": "[format('{0}ds', parameters('assetsStorageAccountName'))]", + "metadata": { + "description": "Optional. The name of the storage account." + } + }, + "assetsStorageAccountContainerName": { + "type": "string", + "defaultValue": "aibscripts", + "metadata": { + "description": "Optional. The name of container in the Storage Account." + } + }, + "virtualNetworkName": { + "type": "string", + "defaultValue": "vnet-it", + "metadata": { + "description": "Optional. The name of the Virtual Network." + } + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "defaultValue": "10.0.0.0/16", + "metadata": { + "description": "Optional. The address space of the Virtual Network." + } + }, + "imageSubnetName": { + "type": "string", + "defaultValue": "subnet-it", + "metadata": { + "description": "Optional. The name of the Image Template Virtual Network Subnet to create." + } + }, + "virtualNetworkSubnetAddressPrefix": { + "type": "string", + "defaultValue": "[cidrSubnet(parameters('virtualNetworkAddressPrefix'), 24, 0)]", + "metadata": { + "description": "Optional. The address space of the Virtual Network Subnet." + } + }, + "deploymentScriptSubnetName": { + "type": "string", + "defaultValue": "subnet-ds", + "metadata": { + "description": "Optional. The name of the Image Template Virtual Network Subnet to create." + } + }, + "virtualNetworkDeploymentScriptSubnetAddressPrefix": { + "type": "string", + "defaultValue": "[cidrSubnet(parameters('virtualNetworkAddressPrefix'), 24, 1)]", + "metadata": { + "description": "Optional. The address space of the Virtual Network Subnet used by the deployment script." + } + }, + "storageDeploymentScriptName": { + "type": "string", + "defaultValue": "ds-triggerUpload-storage", + "metadata": { + "description": "Optional. The name of the Deployment Script to upload files to the assets storage account." + } + }, + "storageAccountFilesToUpload": { + "type": "array", + "items": { + "$ref": "#/definitions/storageAccountFilesToUploadType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The files to upload to the Assets Storage Account." + } + }, + "imageTemplateDeploymentScriptName": { + "type": "string", + "defaultValue": "ds-triggerBuild-imageTemplate", + "metadata": { + "description": "Optional. The name of the Deployment Script to trigger the image template baking." + } + }, + "waitDeploymentScriptName": { + "type": "string", + "defaultValue": "ds-wait-imageTemplate-build", + "metadata": { + "description": "Optional. The name of the Deployment Script to wait for for the image baking to conclude." + } + }, + "imageTemplateName": { + "type": "string", + "defaultValue": "it-aib", + "metadata": { + "description": "Optional. The name of the Image Template." + } + }, + "imageTemplateImageSource": { + "type": "object", + "metadata": { + "description": "Required. The image source to use for the Image Template." + } + }, + "imageTemplateCustomizationSteps": { + "type": "array", + "nullable": true, + "minLength": 1, + "metadata": { + "description": "Optional. The customization steps to use for the Image Template." + } + }, + "computeGalleryImageDefinitionName": { + "type": "string", + "metadata": { + "description": "Required. The name of Image Definition of the Azure Compute Gallery to host the new image version." + } + }, + "waitForImageBuild": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A parameter to control if the deployment should wait for the image build to complete." + } + }, + "waitForImageBuildTimeout": { + "type": "string", + "defaultValue": "PT1H", + "metadata": { + "description": "Optional. A parameter to control the timeout of the deployment script waiting for the image build." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "Optional. The location to deploy into." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a SAS token to access the modules." + } + } + }, + "variables": { + "$fxv#0": "<#\n.SYNOPSIS\nRun the Post-Deployment for the storage account deployment & upload required data to the storage account.\n\n.DESCRIPTION\nRun the Post-Deployment for the storage account deployment & upload required data to the storage account.\nAny content that should be uploaded must exist as an environment variable with a 'script_' prefix (for example 'script_Initialize-LinuxSoftware_ps1').\nThe script will fetch any matching environment variable, store it as a file (for example 'script_Initialize__LinuxSoftware_ps1' is stored as 'Initialize-LinuxSoftware.ps1')\nand uploade it as blob to the given container.\n\n.PARAMETER StorageAccountName\nRequired. The name of the Storage Account to upload to\n\n.PARAMETER TargetContainer\nRequired. The container to upload the files to\n\n.EXAMPLE\n. 'Set-StorageContainerContentByEnvVar.ps1' -StorageAccountName 'mystorage' -TargetContainer 'myContainer'\n\nUpload any required data to the storage account 'mystorage' and container 'myContainer'.\n#>\n\n[CmdletBinding(SupportsShouldProcess = $True)]\nparam(\n [Parameter(Mandatory = $true)]\n [string] $StorageAccountName,\n\n [Parameter(Mandatory = $true)]\n [string] $TargetContainer\n)\n\nWrite-Verbose 'Fetching & storing scripts' -Verbose\n$contentDirectoryName = 'scripts'\n$contentDirectory = (New-Item $contentDirectoryName -ItemType 'Directory' -Force).FullName\n$scriptPaths = @()\nforeach ($scriptEnvVar in (Get-ChildItem 'env:*').Name | Where-Object { $_ -like '__SCRIPT__*' }) {\n # Handle value like 'script_Initialize__LinuxSoftware_ps1'\n $scriptName = $scriptEnvVar -replace '__SCRIPT__', '' -replace '__', '-' -replace '_', '.'\n $scriptContent = (Get-Item env:$scriptEnvVar).Value\n\n Write-Verbose ('Storing file [{0}] with length [{1}]' -f $scriptName, $scriptContent.Length) -Verbose\n $scriptPaths += (New-Item (Join-Path $contentDirectoryName $scriptName) -ItemType 'File' -Value $scriptContent -Force).FullName\n}\n\nWrite-Verbose 'Getting storage account context.' -Verbose\n$ctx = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount\n\nWrite-Verbose 'Building paths to the local folders to upload.' -Verbose\nWrite-Verbose \"Content directory: '$contentDirectory'\" -Verbose\n\nforeach ($scriptPath in $scriptPaths) {\n\n try {\n Write-Verbose 'Testing blob container' -Verbose\n Get-AzStorageContainer -Name $targetContainer -Context $ctx -ErrorAction 'Stop'\n Write-Verbose 'Testing blob container SUCCEEDED' -Verbose\n\n Write-Verbose ('Uploading file [{0}] to container [{1}]' -f (Split-Path $scriptPath -Leaf), $TargetContainer) -Verbose\n if ($PSCmdlet.ShouldProcess(('File [{0}] to container [{1}]' -f (Split-Path $scriptPath -Leaf), $TargetContainer), 'Upload')) {\n $null = Set-AzStorageBlobContent -File $scriptPath -Container $targetContainer -Context $ctx -Force -ErrorAction 'Stop'\n }\n Write-Verbose 'Upload successful' -Verbose\n } catch {\n throw \"Upload FAILED: $_\"\n }\n}\n", + "$fxv#1": "<#\n.SYNOPSIS\nFetch the latest build status for the provided image template\n\n.DESCRIPTION\nFetch the latest build status for the provided image template\n\n.PARAMETER ResourceGroupName\nRequired. The name of the Resource Group containing the image template\n\n.PARAMETER ImageTemplateName\nRequired. The name of the image template to query to build status for. E.g. 'lin_it-2022-02-20-16-17-38'\n\n.EXAMPLE\n. 'Wait-ForImageBuild.ps1' -ResourceGroupName' 'myRG' -ImageTemplateName 'lin_it-2022-02-20-16-17-38'\n\nCheck the current build status of Image Template 'lin_it-2022-02-20-16-17-38' in Resource Group 'myRG'\n#>\n[CmdletBinding()]\nparam(\n [Parameter(Mandatory)]\n [string] $ResourceGroupName,\n\n [Parameter(Mandatory)]\n [string] $ImageTemplateName\n)\n\nbegin {\n Write-Debug ('[{0} entered]' -f $MyInvocation.MyCommand)\n}\n\nprocess {\n # Logic\n # -----\n $context = Get-AzContext\n $subscriptionId = $context.Subscription.Id\n $currentRetry = 1\n $maximumRetries = 720\n $timeToWait = 15\n $maxTimeCalc = '{0:hh\\:mm\\:ss}' -f [timespan]::fromseconds($maximumRetries * $timeToWait)\n do {\n\n # Runnning fetch in retry as it happened that the status was not available\n $statusFetchRetryCount = 3\n $statusFetchCurrentRetry = 1\n do {\n $path = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.VirtualMachineImages/imageTemplates/{2}?api-version=2020-02-14' -f $subscriptionId, $ResourceGroupName, $ImageTemplateName\n $requestInputObject = @{\n Method = 'GET'\n Path = $path\n }\n\n $response = ((Invoke-AzRestMethod @requestInputObject).Content | ConvertFrom-Json).properties\n\n if ($response.lastRunStatus) {\n $latestStatus = $response.lastRunStatus\n break\n }\n Start-Sleep 5\n $statusFetchCurrentRetry++\n } while ($statusFetchCurrentRetry -le $statusFetchRetryCount)\n\n if (-not $latestStatus) {\n Write-Verbose ('Image Build failed with error: [{0}]' -f $response.provisioningError.message) -Verbose\n $latestStatus = 'failed'\n }\n\n\n if ($latestStatus -eq 'failed' -or $latestStatus.runState.ToLower() -eq 'failed') {\n $failedMessage = 'Image Template [{0}] build failed with status [{1}]. API reply: [{2}]' -f $ImageTemplateName, $latestStatus.runState, $response.lastRunStatus.message\n Write-Verbose $failedMessage -Verbose\n throw $failedMessage\n }\n\n if ($latestStatus.runState.ToLower() -notIn @('running', 'new')) {\n break\n }\n\n $currTimeCalc = '{0:hh\\:mm\\:ss}' -f [timespan]::fromseconds($currentRetry * $timeToWait)\n\n Write-Verbose ('[{0}] Waiting 15 seconds [{1}|{2}]' -f (Get-Date -Format 'HH:mm:ss'), $currTimeCalc, $maxTimeCalc) -Verbose\n $currentRetry++\n Start-Sleep $timeToWait\n } while ($currentRetry -le $maximumRetries)\n\n if ($latestStatus) {\n $duration = New-TimeSpan -Start $latestStatus.startTime -End $latestStatus.endTime\n Write-Verbose ('It took [{0}] minutes and [{1}] seconds to build and distribute the image.' -f $duration.Minutes, $duration.Seconds) -Verbose\n } else {\n Write-Warning \"Timeout at [$currTimeCalc]. Note, the Azure Image Builder may still succeed.\"\n }\n return $latestStatus\n}\n\nend {\n Write-Debug ('[{0} existed]' -f $MyInvocation.MyCommand)\n}\n", + "formattedTime": "[replace(replace(replace(parameters('baseTime'), ':', ''), '-', ''), ' ', '')]" + }, + "resources": { + "storageFileDataPrivilegedContributorRole": { + "existing": true, + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2022-04-01", + "scope": "/", + "name": "69566ab7-960f-475b-8e7c-b3118f30c6bd" + }, + "contributorRole": { + "existing": true, + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2022-04-01", + "scope": "/", + "name": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.ptn.vmimages-azureimagebuilder.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "location": "[parameters('location')]", + "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" + } + } + } + } + }, + "rg": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('location')]" + }, + "imageTemplateRg": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "name": "[parameters('imageTemplateResourceGroupName')]", + "location": "[parameters('location')]" + }, + "imageMSI_rbac": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, format('{0}/resourceGroups/{1}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{2}', subscription().id, parameters('resourceGroupName'), parameters('imageManagedIdentityName')), tenantResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c'))]", + "properties": { + "principalId": "[if(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base')), reference('imageMSI').outputs.principalId.value, '')]", + "roleDefinitionId": "[tenantResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "contributorRole", + "imageMSI" + ] + }, + "dsMsi_existing": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'Only assets & image'), equals(parameters('deploymentsToPerform'), 'Only image'))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "resourceGroup": "[parameters('resourceGroupName')]", + "name": "[parameters('deploymentScriptManagedIdentityName')]" + }, + "dsMsi": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ds-msi', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('deploymentScriptManagedIdentityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "10609859695208799167" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity.", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "federatedIdentityCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "$ref": "#/definitions/federatedIdentityCredentialsType", + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "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": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "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": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "userAssignedIdentity_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.ManagedIdentity/userAssignedIdentities/{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": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCredential-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "3716898257490923786" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2023-01-31", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" + } + } + } + }, + "dependsOn": [ + "rg" + ] + }, + "imageMSI": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-image-msi', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('imageManagedIdentityName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "10609859695208799167" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity.", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "federatedIdentityCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "$ref": "#/definitions/federatedIdentityCredentialsType", + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "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": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "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": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "userAssignedIdentity_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.ManagedIdentity/userAssignedIdentities/{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": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCredential-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "3716898257490923786" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2023-01-31", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" + } + } + } + }, + "dependsOn": [ + "rg" + ] + }, + "azureComputeGallery": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-acg', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('computeGalleryName')]" + }, + "images": { + "value": "[parameters('computeGalleryImageDefinitions')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "3415776249412580608" + }, + "name": "Azure Compute Galleries", + "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).", + "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." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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." + } + } + } + } + }, + "imageType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the image definition." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery image definition resource. This property is updatable." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." + } + }, + "osState": { + "type": "string", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Required. This property allows the user to specify the state of the OS of the image." + } + }, + "identifier": { + "$ref": "#/definitions/identifierType", + "metadata": { + "description": "Required. This is the gallery image definition identifier." + } + }, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the resource range (1-128 CPU cores). Defaults to min=1, max=4." + } + }, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the resource range (1-4000 GB RAM). Defaults to min=4, max=16." + } + }, + "hyperVGeneration": { + "type": "string", + "allowedValues": [ + "V1", + "V2" + ], + "nullable": true, + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." + } + }, + "securityType": { + "type": "string", + "allowedValues": [ + "ConfidentialVM", + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch" + ], + "nullable": true, + "metadata": { + "description": "Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`." + } + }, + "isAcceleratedNetworkSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specify if the image supports accelerated networking. Defaults to true." + } + }, + "isHibernateSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifiy if the image supports hibernation." + } + }, + "architecture": { + "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], + "nullable": true, + "metadata": { + "description": "Optional. The architecture of the image. Applicable to OS disks only." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery image definition." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." + } + }, + "endOfLife": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "excludedDiskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Describes the disallowed disk types." + } + } + } + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "image/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Required. Name of the Azure Compute Gallery." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the Azure Shared Image Gallery." + } + }, + "applications": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Applications to create." + } + }, + "images": { + "type": "array", + "items": { + "$ref": "#/definitions/imageType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Images to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n key1: 'value1'\n key2: 'value2'\n }\n ", + "description": "Optional. Tags for all resources." + } + }, + "sharingProfile": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Profile for gallery sharing to subscription or tenant." + } + }, + "softDeletePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Soft deletion policy of the gallery." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.compute-gallery.{0}.{1}', replace('0.7.0', '.', '-'), 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" + } + } + } + } + }, + "gallery": { + "type": "Microsoft.Compute/galleries", + "apiVersion": "2023-07-03", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "description": "[parameters('description')]", + "sharingProfile": "[parameters('sharingProfile')]", + "softDeletePolicy": "[parameters('softDeletePolicy')]" + } + }, + "gallery_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.Compute/galleries/{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": [ + "gallery" + ] + }, + "gallery_roleAssignments": { + "copy": { + "name": "gallery_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "gallery" + ] + }, + "galleries_applications": { + "copy": { + "name": "galleries_applications", + "count": "[length(coalesce(parameters('applications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Gallery-Application-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].name]" + }, + "galleryName": { + "value": "[parameters('name')]" + }, + "supportedOSType": { + "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].supportedOSType]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'description')]" + }, + "eula": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'eula')]" + }, + "privacyStatementUri": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'privacyStatementUri')]" + }, + "releaseNoteUri": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'releaseNoteUri')]" + }, + "endOfLifeDate": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'endOfLifeDate')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "customActions": { + "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'customActions')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "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.29.47.4906", + "templateHash": "7960057132021914503" + }, + "name": "Compute Galleries Applications", + "description": "This module deploys an Azure Compute Gallery Application.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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", + "metadata": { + "description": "Required. Name of the application definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "galleryName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery Application Definition resource. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery Application Definition. Has to be a valid URL." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri. Has to be a valid URL." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "supportedOSType": { + "type": "string", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Required. This property allows you to specify the supported type of the OS that application is built for." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags for all resources." + } + }, + "customActions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. A list of custom actions that can be performed with all of the Gallery Application Versions within this Gallery Application." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "gallery": { + "existing": true, + "type": "Microsoft.Compute/galleries", + "apiVersion": "2022-03-03", + "name": "[parameters('galleryName')]" + }, + "application": { + "type": "Microsoft.Compute/galleries/applications", + "apiVersion": "2022-03-03", + "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "customActions": "[parameters('customActions')]", + "description": "[parameters('description')]", + "endOfLifeDate": "[parameters('endOfLifeDate')]", + "eula": "[parameters('eula')]", + "privacyStatementUri": "[parameters('privacyStatementUri')]", + "releaseNoteUri": "[parameters('releaseNoteUri')]", + "supportedOSType": "[parameters('supportedOSType')]" + }, + "dependsOn": [ + "gallery" + ] + }, + "application_roleAssignments": { + "copy": { + "name": "application_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}/applications/{1}', parameters('galleryName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "application" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/galleries/applications', parameters('galleryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('application', '2022-03-03', 'full').location]" + } + } + } + }, + "dependsOn": [ + "gallery" + ] + }, + "galleries_images": { + "copy": { + "name": "galleries_images", + "count": "[length(coalesce(parameters('images'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Gallery-Image-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "galleryName": { + "value": "[parameters('name')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'description')]" + }, + "osType": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osType]" + }, + "osState": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osState]" + }, + "identifier": { + "value": "[coalesce(parameters('images'), createArray())[copyIndex()].identifier]" + }, + "vCPUs": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'vCPUs')]" + }, + "memory": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'memory')]" + }, + "hyperVGeneration": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'hyperVGeneration')]" + }, + "securityType": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'securityType')]" + }, + "isAcceleratedNetworkSupported": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isAcceleratedNetworkSupported')]" + }, + "isHibernateSupported": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isHibernateSupported')]" + }, + "architecture": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'architecture')]" + }, + "eula": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'eula')]" + }, + "privacyStatementUri": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'privacyStatementUri')]" + }, + "releaseNoteUri": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'releaseNoteUri')]" + }, + "purchasePlan": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'purchasePlan')]" + }, + "endOfLifeDate": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'endOfLife')]" + }, + "disallowed": { + "value": { + "diskTypes": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'excludedDiskTypes'), createArray())]" + } + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "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.29.47.4906", + "templateHash": "17284709546040050431" + }, + "name": "Compute Galleries Image Definitions", + "description": "This module deploys an Azure Compute Gallery Image Definition.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "resourceRangeType": { + "type": "object", + "properties": { + "min": { + "type": "int", + "nullable": true, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + }, + "max": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of the resource." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disallowedType": { + "type": "object", + "properties": { + "diskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "example": " [\n 'Standard_LRS'\n ]", + "description": "Required. A list of disk types." + } + } + }, + "nullable": true + }, + "identifierType": { + "type": "object", + "properties": { + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition publisher." + } + }, + "offer": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition offer." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. The name of the gallery image definition SKU." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "purchasePlanType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The plan ID." + } + }, + "product": { + "type": "string", + "metadata": { + "description": "Required. The product ID." + } + }, + "publisher": { + "type": "string", + "metadata": { + "description": "Required. The publisher ID." + } + } + }, + "nullable": true, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80, + "metadata": { + "description": "Required. Name of the image definition." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "galleryName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Conditional. The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment." + } + }, + "identifier": { + "$ref": "#/definitions/identifierType", + "metadata": { + "description": "Required. This is the gallery image definition identifier." + } + }, + "osState": { + "type": "string", + "allowedValues": [ + "Generalized", + "Specialized" + ], + "metadata": { + "description": "Required. This property allows the user to specify the state of the OS of the image." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Required. This property allows you to specify the type of the OS that is included in the disk when creating a VM from a managed image." + } + }, + "privacyStatementUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The privacy statement uri." + } + }, + "purchasePlan": { + "$ref": "#/definitions/purchasePlanType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the gallery image definition purchase plan. This is used by marketplace images." + } + }, + "vCPUs": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 1, + "max": 4 + }, + "metadata": { + "description": "Optional. Describes the resource range (1-128 CPU cores)." + } + }, + "memory": { + "$ref": "#/definitions/resourceRangeType", + "defaultValue": { + "min": 4, + "max": 16 + }, + "metadata": { + "description": "Optional. Describes the resource range (1-4000 GB RAM)." + } + }, + "releaseNoteUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The release note uri. Has to be a valid URL." + } + }, + "securityType": { + "type": "string", + "allowedValues": [ + "ConfidentialVM", + "ConfidentialVMSupported", + "Standard", + "TrustedLaunch" + ], + "nullable": true, + "metadata": { + "description": "Optional. The security type of the image. Requires a hyperVGeneration V2." + } + }, + "isAcceleratedNetworkSupported": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specify if the image supports accelerated networking." + } + }, + "isHibernateSupported": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifiy if the image supports hibernation." + } + }, + "architecture": { + "type": "string", + "allowedValues": [ + "Arm64", + "x64" + ], + "nullable": true, + "metadata": { + "description": "Optional. The architecture of the image. Applicable to OS disks only." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this gallery image definition resource. This property is updatable." + } + }, + "disallowed": { + "$ref": "#/definitions/disallowedType", + "nullable": true, + "metadata": { + "description": "Optional. Describes the disallowed disk types." + } + }, + "endOfLifeDate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The end of life date of the gallery image definition. This property can be used for decommissioning purposes. This property is updatable." + } + }, + "eula": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Eula agreement for the gallery image definition." + } + }, + "hyperVGeneration": { + "type": "string", + "allowedValues": [ + "V1", + "V2" + ], + "nullable": true, + "metadata": { + "description": "Optional. The hypervisor generation of the Virtual Machine. If this value is not specified, then it is determined by the securityType parameter. If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": "{\n key1: 'value1'\n key2: 'value2'\n}\n", + "description": "Optional. Tags for all the image." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Compute Gallery Sharing Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "gallery": { + "existing": true, + "type": "Microsoft.Compute/galleries", + "apiVersion": "2023-07-03", + "name": "[parameters('galleryName')]" + }, + "image": { + "type": "Microsoft.Compute/galleries/images", + "apiVersion": "2023-07-03", + "name": "[format('{0}/{1}', parameters('galleryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "architecture": "[parameters('architecture')]", + "description": "[parameters('description')]", + "disallowed": { + "diskTypes": "[coalesce(tryGet(parameters('disallowed'), 'diskTypes'), createArray())]" + }, + "endOfLifeDate": "[parameters('endOfLifeDate')]", + "eula": "[parameters('eula')]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", + "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", + "identifier": { + "publisher": "[parameters('identifier').publisher]", + "offer": "[parameters('identifier').offer]", + "sku": "[parameters('identifier').sku]" + }, + "osState": "[parameters('osState')]", + "osType": "[parameters('osType')]", + "privacyStatementUri": "[parameters('privacyStatementUri')]", + "purchasePlan": "[coalesce(parameters('purchasePlan'), null())]", + "recommended": { + "vCPUs": "[parameters('vCPUs')]", + "memory": "[parameters('memory')]" + }, + "releaseNoteUri": "[parameters('releaseNoteUri')]" + }, + "dependsOn": [ + "gallery" + ] + }, + "image_roleAssignments": { + "copy": { + "name": "image_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}/images/{1}', parameters('galleryName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "image" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image." + }, + "value": "[resourceId('Microsoft.Compute/galleries/images', parameters('galleryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the image." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('image', '2023-07-03', 'full').location]" + } + } + } + }, + "dependsOn": [ + "gallery" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed image gallery." + }, + "value": "[resourceId('Microsoft.Compute/galleries', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed image gallery." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed image gallery." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('gallery', '2023-07-03', 'full').location]" + }, + "imageResourceIds": { + "type": "array", + "metadata": { + "description": "The resource ids of the deployed images." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('images'), createArray()))))]", + "input": "[reference(format('galleries_images[{0}]', range(0, length(coalesce(parameters('images'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + } + } + } + }, + "dependsOn": [ + "rg" + ] + }, + "vnet": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-vnet', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('virtualNetworkName')]" + }, + "addressPrefixes": { + "value": [ + "[parameters('virtualNetworkAddressPrefix')]" + ] + }, + "subnets": { + "value": [ + { + "name": "[parameters('imageSubnetName')]", + "addressPrefix": "[parameters('virtualNetworkSubnetAddressPrefix')]", + "privateLinkServiceNetworkPolicies": "Disabled", + "serviceEndpoints": [ + "Microsoft.Storage" + ] + }, + { + "name": "[parameters('deploymentScriptSubnetName')]", + "addressPrefix": "[parameters('virtualNetworkDeploymentScriptSubnetAddressPrefix')]", + "privateLinkServiceNetworkPolicies": "Disabled", + "serviceEndpoints": [ + "Microsoft.Storage" + ], + "delegation": "Microsoft.ContainerInstance/containerGroups" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "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.29.47.4906", + "templateHash": "15949466154563447171" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "peeringType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + }, + "remotePeeringEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Deploy the outbound and the inbound peering." + } + }, + "remotePeeringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." + } + }, + "remotePeeringAllowForwardedTraffic": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "remotePeeringAllowGatewayTransit": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "remotePeeringAllowVirtualNetworkAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "remotePeeringDoNotVerifyRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." + } + }, + "remotePeeringUseRemoteGateways": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + } + }, + "subnetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Name of the subnet resource." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "allowedValues": [ + "", + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. enable or disable apply network policies on private link service in the subnet." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Virtual Network (vNet)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." + } + }, + "virtualNetworkBgpCommunity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The BGP community associated with the virtual network." + } + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/subnetType" + }, + "nullable": true, + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." + } + }, + "peerings": { + "type": "array", + "items": { + "$ref": "#/definitions/peeringType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Virtual Network Peering configurations." + } + }, + "vnetEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." + } + }, + "vnetEncryptionEnforcement": { + "type": "string", + "defaultValue": "AllowUnencrypted", + "allowedValues": [ + "AllowUnencrypted", + "DropUnencrypted" + ], + "metadata": { + "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." + } + }, + "flowTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "maxValue": 30, + "metadata": { + "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "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." + } + }, + "enableVmProtection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "virtualNetwork": { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": { + "addressPrefixes": "[parameters('addressPrefixes')]" + }, + "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", + "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", + "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", + "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", + "enableVmProtection": "[parameters('enableVmProtection')]" + } + }, + "virtualNetwork_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/virtualNetworks/{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": [ + "virtualNetwork" + ] + }, + "virtualNetwork_diagnosticSettings": { + "copy": { + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_roleAssignments": { + "copy": { + "name": "virtualNetwork_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "virtualNetworkName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" + }, + "addressPrefix": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" + }, + "addressPrefixes": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" + }, + "applicationGatewayIPConfigurations": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" + }, + "delegation": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" + }, + "natGatewayResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" + }, + "networkSecurityGroupResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" + }, + "privateEndpointNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" + }, + "privateLinkServiceNetworkPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "routeTableResourceId": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" + }, + "serviceEndpointPolicies": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" + }, + "serviceEndpoints": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" + }, + "defaultOutboundAccess": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" + }, + "sharingScope": { + "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" + } + }, + "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.29.47.4906", + "templateHash": "5699372618313647761" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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", + "metadata": { + "description": "Requird. The Name of the subnet resource." + } + }, + "virtualNetworkName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." + } + }, + "addressPrefix": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." + } + }, + "networkSecurityGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the network security group to assign to the subnet." + } + }, + "routeTableResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the route table to assign to the subnet." + } + }, + "serviceEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The service endpoints to enable on the subnet." + } + }, + "delegation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The delegation to enable on the subnet." + } + }, + "natGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." + } + }, + "privateEndpointNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." + } + }, + "privateLinkServiceNetworkPolicies": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "Disabled", + "Enabled", + "" + ], + "metadata": { + "description": "Optional. Enable or disable apply network policies on private link service in the subnet." + } + }, + "addressPrefixes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." + } + }, + "defaultOutboundAccess": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." + } + }, + "sharingScope": { + "type": "string", + "allowedValues": [ + "DelegatedServices", + "Tenant" + ], + "nullable": true, + "metadata": { + "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." + } + }, + "applicationGatewayIPConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application gateway IP configurations of virtual network resource." + } + }, + "serviceEndpointPolicies": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of service endpoint policies." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2024-01-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "serviceEndpoints", + "count": "[length(parameters('serviceEndpoints'))]", + "input": { + "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" + } + } + ], + "addressPrefix": "[parameters('addressPrefix')]", + "addressPrefixes": "[parameters('addressPrefixes')]", + "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", + "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", + "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", + "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", + "privateEndpointNetworkPolicies": "[if(not(empty(parameters('privateEndpointNetworkPolicies'))), parameters('privateEndpointNetworkPolicies'), null())]", + "privateLinkServiceNetworkPolicies": "[if(not(empty(parameters('privateLinkServiceNetworkPolicies'))), parameters('privateLinkServiceNetworkPolicies'), null())]", + "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", + "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", + "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", + "sharingScope": "[parameters('sharingScope')]" + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "subnet_roleAssignments": { + "copy": { + "name": "subnet_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "subnet" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" + }, + "addressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" + }, + "addressPrefixes": { + "type": "array", + "metadata": { + "description": "List of address prefixes for the subnet." + }, + "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[parameters('name')]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + }, + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(coalesce(parameters('peerings'), createArray()))]" + }, + "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", + "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" + }, + "allowForwardedTraffic": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" + }, + "allowGatewayTransit": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" + }, + "allowVirtualNetworkAccess": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" + }, + "doNotVerifyRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" + }, + "useRemoteGateways": { + "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5206620163504251868" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", + "metadata": { + "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." + } + }, + "localVnetName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." + } + }, + "remoteVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." + } + }, + "allowForwardedTraffic": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." + } + }, + "allowGatewayTransit": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." + } + }, + "allowVirtualNetworkAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." + } + }, + "doNotVerifyRemoteGateways": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." + } + }, + "useRemoteGateways": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2024-01-01", + "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "properties": { + "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", + "allowGatewayTransit": "[parameters('allowGatewayTransit')]", + "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", + "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", + "useRemoteGateways": "[parameters('useRemoteGateways')]", + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network peering was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network peering." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network peering." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "virtualNetwork" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the virtual network was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the virtual network." + }, + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" + }, + "subnetNames": { + "type": "array", + "metadata": { + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" + } + }, + "subnetResourceIds": { + "type": "array", + "metadata": { + "description": "The resource IDs of the deployed subnets." + }, + "copy": { + "count": "[length(coalesce(parameters('subnets'), createArray()))]", + "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "rg" + ] + }, + "assetsStorageAccount": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-files-sa', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('assetsStorageAccountName')]" + }, + "allowSharedKeyAccess": { + "value": false + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "networkAcls": { + "value": { + "defaultAction": "Allow" + } + }, + "blobServices": { + "value": { + "containers": [ + { + "name": "[parameters('assetsStorageAccountContainerName')]", + "publicAccess": "None", + "roleAssignments": [ + { + "roleDefinitionIdOrName": "Storage Blob Data Contributor", + "principalId": "[if(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base')), reference('dsMsi').outputs.principalId.value, '')]", + "principalType": "ServicePrincipal" + }, + { + "roleDefinitionIdOrName": "Storage Blob Data Reader", + "principalId": "[if(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base')), reference('imageMSI').outputs.principalId.value, '')]", + "principalType": "ServicePrincipal" + } + ] + } + ], + "containerDeleteRetentionPolicyEnabled": true, + "containerDeleteRetentionPolicyDays": 10 + } + } + }, + "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.28.1.47646", + "templateHash": "3958760216991467865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "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 + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The Storage Account ManagementPolicies Rules." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "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." + } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + } + }, + "variables": { + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "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(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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.9.1', '.', '-'), 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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_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.Storage/storageAccounts/{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": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts', 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": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote 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')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', 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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(parameters('managementPolicyRules'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[coalesce(parameters('managementPolicyRules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "9473195527943694039" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "description": "Required. The Storage Account ManagementPolicies Rules." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + }, + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(parameters('localUsers'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('localUsers')[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[parameters('localUsers')[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[parameters('localUsers')[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[parameters('localUsers')[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'sshAuthorizedKeys')]" + } + }, + "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.28.1.47646", + "templateHash": "14968464858285923305" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "sshAuthorizedKeysType": { + "type": "secureObject", + "properties": { + "secureList": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "string", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + } + }, + "metadata": { + "description": "Optional. The list of SSH authorized keys." + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "$ref": "#/definitions/sshAuthorizedKeysType", + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[tryGet(parameters('sshAuthorizedKeys'), 'secureList')]" + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "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.28.1.47646", + "templateHash": "2306287879023715578" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies CORS rules for the Blob service. You can include up to five CorsRule elements in the request. If no CorsRule elements are included in the request body, all CORS rules will be deleted, and CORS will be disabled for the Blob service." + } + }, + "defaultServiceVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 6, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": { + "corsRules": "[parameters('corsRules')]" + }, + "defaultServiceVersion": "[if(not(empty(parameters('defaultServiceVersion'))), parameters('defaultServiceVersion'), null())]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(not(equals(reference('storageAccount', '2022-09-01', 'full').kind, 'Storage')), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicyProperties": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicyProperties')]" + } + }, + "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.28.1.47646", + "templateHash": "7045309160947869799" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicyName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. Name of the immutable policy." + } + }, + "immutabilityPolicyProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair to associate with the container as metadata." + } + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(equals(parameters('immutableStorageWithVersioningEnabled'), true()), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + }, + "dependsOn": [ + "storageAccount::blobServices" + ] + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', 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": [ + "container" + ] + }, + "immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicyProperties'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('immutabilityPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWritesAll')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "2543276032744560941" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "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.28.1.47646", + "templateHash": "7463227074634701879" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "1342480740201032357" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + }, + "dependsOn": [ + "storageAccount::fileService" + ] + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "8779226603522513073" + } + }, + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "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", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "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" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[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": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + } + }, + "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.28.1.47646", + "templateHash": "10678250016540336570" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "13487964166280180730" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Required. A name-value pair that represents queue metadata." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + }, + "dependsOn": [ + "storageAccount::queueServices" + ] + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', 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": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + } + }, + "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.28.1.47646", + "templateHash": "16839054392438941735" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "3177845984945141330" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "dependsOn": [ + "storageAccount::tableServices" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', 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": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "dsMsi", + "imageMSI", + "rg" + ] + }, + "dsStorageAccount": { + "condition": "[or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ds-sa', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('deploymentScriptStorageAccountName')]" + }, + "allowSharedKeyAccess": { + "value": true + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "[tenantResourceId('Microsoft.Authorization/roleDefinitions', '69566ab7-960f-475b-8e7c-b3118f30c6bd')]", + "principalId": "[if(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base')), reference('dsMsi').outputs.principalId.value, '')]", + "principalType": "ServicePrincipal" + } + ] + }, + "location": { + "value": "[parameters('location')]" + }, + "networkAcls": { + "value": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "virtualNetworkRules": [ + { + "action": "Allow", + "id": "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('deploymentScriptSubnetName'))]" + } + ] + } + } + }, + "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.28.1.47646", + "templateHash": "3958760216991467865" + }, + "name": "Storage Accounts", + "description": "This module deploys a Storage Account.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "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 + }, + "networkAclsType": { + "type": "object", + "properties": { + "resourceAccessRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The ID of the tenant in which the resource resides in." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target service. Can also contain a wildcard, if multiple services e.g. in a resource group should be included." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Sets the resource access rules. Array entries must consist of \"tenantId\" and \"resourceId\" fields only." + } + }, + "bypass": { + "type": "string", + "allowedValues": [ + "AzureServices", + "AzureServices, Logging", + "AzureServices, Logging, Metrics", + "AzureServices, Metrics", + "Logging", + "Logging, Metrics", + "Metrics", + "None" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging,Metrics,AzureServices (For example, \"Logging, Metrics\"), or None to bypass none of those traffics." + } + }, + "virtualNetworkRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the virtual network rules." + } + }, + "ipRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Sets the IP ACL rules." + } + }, + "defaultAction": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the default action of allow or deny when no other rules match." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "metadata": { + "description": "Required. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. If used must also be specified in `managedIdentities.userAssignedResourceIds`. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Storage Account. Must be lower-case." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "kind": { + "type": "string", + "defaultValue": "StorageV2", + "allowedValues": [ + "Storage", + "StorageV2", + "BlobStorage", + "FileStorage", + "BlockBlobStorage" + ], + "metadata": { + "description": "Optional. Type of Storage Account to create." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "allowedValues": [ + "Standard_LRS", + "Standard_GRS", + "Standard_RAGRS", + "Standard_ZRS", + "Premium_LRS", + "Premium_ZRS", + "Standard_GZRS", + "Standard_RAGZRS" + ], + "metadata": { + "description": "Optional. Storage Account Sku Name." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Premium", + "Hot", + "Cool" + ], + "metadata": { + "description": "Conditional. Required if the Storage Account kind is set to BlobStorage. The access tier is used for billing. The \"Premium\" access tier is the default value for premium block blobs storage account type and it cannot be changed for the premium block blobs storage account type." + } + }, + "largeFileSharesState": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Allow large file shares if sets to 'Enabled'. It cannot be disabled once it is enabled. Only supported on locally redundant and zone redundant file shares. It cannot be set on FileStorage storage accounts (storage accounts for premium file shares)." + } + }, + "azureFilesIdentityBasedAuthentication": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Provides the identity based authentication settings for Azure Files." + } + }, + "defaultToOAuthAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean flag which indicates whether the default authentication is OAuth or not." + } + }, + "allowSharedKeyAccess": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the storage account permits requests to be authorized with the account access key via Shared Key. If false, then all requests, including shared access signatures, must be authorized with Azure Active Directory (Azure AD). The default value is null, which is equivalent to true." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "managementPolicyRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The Storage Account ManagementPolicies Rules." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. A Boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. For security reasons, it is recommended to set it to true." + } + }, + "allowCrossTenantReplication": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow or disallow cross AAD tenant object replication." + } + }, + "customDomainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Sets the custom domain name assigned to the storage account. Name is the CNAME source." + } + }, + "customDomainUseSubDomainName": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether indirect CName validation is enabled. This should only be set on updates." + } + }, + "dnsEndpointType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AzureDnsZone", + "Standard" + ], + "metadata": { + "description": "Optional. Allows you to specify the type of endpoint. Set this to AzureDNSZone to create a large number of accounts in a single subscription, which creates accounts in an Azure DNS Zone and the endpoint URL will have an alphanumeric DNS Zone identifier." + } + }, + "blobServices": { + "type": "object", + "defaultValue": "[if(not(equals(parameters('kind'), 'FileStorage')), createObject('containerDeleteRetentionPolicyEnabled', true(), 'containerDeleteRetentionPolicyDays', 7, 'deleteRetentionPolicyEnabled', true(), 'deleteRetentionPolicyDays', 6), createObject())]", + "metadata": { + "description": "Optional. Blob service and containers to deploy." + } + }, + "fileServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. File service and shares to deploy." + } + }, + "queueServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Queue service and queues to create." + } + }, + "tableServices": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table service and tables to create." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account. For security reasons, it is recommended to set it to false." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "TLS1_2", + "allowedValues": [ + "TLS1_0", + "TLS1_1", + "TLS1_2" + ], + "metadata": { + "description": "Optional. Set the minimum TLS version on request to storage." + } + }, + "enableHierarchicalNamespace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true." + } + }, + "enableSftp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables Secure File Transfer Protocol for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "localUsers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Local users to deploy for SFTP authentication." + } + }, + "isLocalUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables local users feature, if set to true." + } + }, + "enableNfsV3": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, enables NFS 3.0 support for the storage account. Requires enableHierarchicalNamespace to be true." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "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." + } + }, + "allowedCopyScope": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "AAD", + "PrivateLink" + ], + "metadata": { + "description": "Optional. Restrict copy to and from Storage Accounts within an AAD tenant or with Private Links to the same VNet." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "supportsHttpsTrafficOnly": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allows HTTPS traffic only to storage service if sets to true." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "sasExpirationPeriod": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The SAS expiration period. DD.HH:MM:SS." + } + }, + "keyType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Account", + "Service" + ], + "metadata": { + "description": "Optional. The keyType to use with Queue & Table services." + } + } + }, + "variables": { + "supportsBlobService": "[or(or(or(equals(parameters('kind'), 'BlockBlobStorage'), equals(parameters('kind'), 'BlobStorage')), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "supportsFileService": "[or(or(equals(parameters('kind'), 'FileStorage'), equals(parameters('kind'), 'StorageV2')), equals(parameters('kind'), 'Storage'))]", + "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(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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.storage-storageaccount.{0}.{1}', replace('0.9.1', '.', '-'), 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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "storageAccount": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "kind": "[parameters('kind')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "properties": { + "allowSharedKeyAccess": "[parameters('allowSharedKeyAccess')]", + "defaultToOAuthAuthentication": "[parameters('defaultToOAuthAuthentication')]", + "allowCrossTenantReplication": "[parameters('allowCrossTenantReplication')]", + "allowedCopyScope": "[if(not(empty(parameters('allowedCopyScope'))), parameters('allowedCopyScope'), null())]", + "customDomain": { + "name": "[parameters('customDomainName')]", + "useSubDomainName": "[parameters('customDomainUseSubDomainName')]" + }, + "dnsEndpointType": "[if(not(empty(parameters('dnsEndpointType'))), parameters('dnsEndpointType'), null())]", + "isLocalUserEnabled": "[parameters('isLocalUserEnabled')]", + "encryption": "[union(createObject('keySource', if(not(empty(parameters('customerManagedKey'))), 'Microsoft.Keyvault', 'Microsoft.Storage'), 'services', createObject('blob', if(variables('supportsBlobService'), createObject('enabled', true()), null()), 'file', if(variables('supportsFileService'), createObject('enabled', true()), null()), 'table', createObject('enabled', true(), 'keyType', parameters('keyType')), 'queue', createObject('enabled', true(), 'keyType', parameters('keyType'))), 'keyvaultproperties', if(not(empty(parameters('customerManagedKey'))), createObject('keyname', parameters('customerManagedKey').keyName, 'keyvaulturi', reference('cMKKeyVault').vaultUri, 'keyversion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/')))), null()), 'identity', createObject('userAssignedIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))), null()))), if(parameters('requireInfrastructureEncryption'), createObject('requireInfrastructureEncryption', if(not(equals(parameters('kind'), 'Storage')), parameters('requireInfrastructureEncryption'), null())), createObject()))]", + "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", + "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", + "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", + "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isSftpEnabled": "[parameters('enableSftp')]", + "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", + "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]", + "networkAcls": "[if(not(empty(parameters('networkAcls'))), union(createObject('resourceAccessRules', tryGet(parameters('networkAcls'), 'resourceAccessRules'), 'defaultAction', coalesce(tryGet(parameters('networkAcls'), 'defaultAction'), 'Deny'), 'virtualNetworkRules', tryGet(parameters('networkAcls'), 'virtualNetworkRules'), 'ipRules', tryGet(parameters('networkAcls'), 'ipRules')), if(contains(parameters('networkAcls'), 'bypass'), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass')), createObject())), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkAcls'))), 'Disabled', null()))]", + "azureFilesIdentityBasedAuthentication": "[if(not(empty(parameters('azureFilesIdentityBasedAuthentication'))), parameters('azureFilesIdentityBasedAuthentication'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "storageAccount_diagnosticSettings": { + "copy": { + "name": "storageAccount_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_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.Storage/storageAccounts/{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": [ + "storageAccount" + ] + }, + "storageAccount_roleAssignments": { + "copy": { + "name": "storageAccount_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts', 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": [ + "storageAccount" + ] + }, + "storageAccount_privateEndpoints": { + "copy": { + "name": "storageAccount_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-StorageAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Storage/storageAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote 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')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', 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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_managementPolicies": { + "condition": "[not(empty(coalesce(parameters('managementPolicyRules'), createArray())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-ManagementPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "rules": { + "value": "[coalesce(parameters('managementPolicyRules'), createArray())]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "9473195527943694039" + }, + "name": "Storage Account Management Policies", + "description": "This module deploys a Storage Account Management Policy.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "rules": { + "type": "array", + "metadata": { + "description": "Required. The Storage Account ManagementPolicies Rules." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/managementPolicies", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "properties": { + "policy": { + "rules": "[parameters('rules')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed management policy." + }, + "value": "default" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed management policy." + }, + "value": "default" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed management policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount", + "storageAccount_blobServices" + ] + }, + "storageAccount_localUsers": { + "copy": { + "name": "storageAccount_localUsers", + "count": "[length(parameters('localUsers'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-LocalUsers-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('localUsers')[copyIndex()].name]" + }, + "hasSshKey": { + "value": "[parameters('localUsers')[copyIndex()].hasSshKey]" + }, + "hasSshPassword": { + "value": "[parameters('localUsers')[copyIndex()].hasSshPassword]" + }, + "permissionScopes": { + "value": "[parameters('localUsers')[copyIndex()].permissionScopes]" + }, + "hasSharedKey": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'hasSharedKey')]" + }, + "homeDirectory": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'homeDirectory')]" + }, + "sshAuthorizedKeys": { + "value": "[tryGet(parameters('localUsers')[copyIndex()], 'sshAuthorizedKeys')]" + } + }, + "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.28.1.47646", + "templateHash": "14968464858285923305" + }, + "name": "Storage Account Local Users", + "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "sshAuthorizedKeysType": { + "type": "secureObject", + "properties": { + "secureList": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description used to store the function/usage of the key." + } + }, + "key": { + "type": "string", + "metadata": { + "description": "Required. SSH public key base64 encoded. The format should be: '{keyType} {keyData}', e.g. ssh-rsa AAAABBBB." + } + } + } + }, + "metadata": { + "description": "Optional. The list of SSH authorized keys." + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the local user used for SFTP Authentication." + } + }, + "hasSharedKey": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether shared key exists. Set it to false to remove existing shared key." + } + }, + "hasSshKey": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH key exists. Set it to false to remove existing SSH key." + } + }, + "hasSshPassword": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether SSH password exists. Set it to false to remove existing SSH password." + } + }, + "homeDirectory": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The local user home directory." + } + }, + "permissionScopes": { + "type": "array", + "metadata": { + "description": "Required. The permission scopes of the local user." + } + }, + "sshAuthorizedKeys": { + "$ref": "#/definitions/sshAuthorizedKeysType", + "metadata": { + "description": "Optional. The local user SSH authorized keys for SFTP." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "localUsers": { + "type": "Microsoft.Storage/storageAccounts/localUsers", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "hasSharedKey": "[parameters('hasSharedKey')]", + "hasSshKey": "[parameters('hasSshKey')]", + "hasSshPassword": "[parameters('hasSshPassword')]", + "homeDirectory": "[parameters('homeDirectory')]", + "permissionScopes": "[parameters('permissionScopes')]", + "sshAuthorizedKeys": "[tryGet(parameters('sshAuthorizedKeys'), 'secureList')]" + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed local user." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed local user." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed local user." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/localUsers', parameters('storageAccountName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_blobServices": { + "condition": "[not(empty(parameters('blobServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-BlobServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('blobServices'), 'containers')]" + }, + "automaticSnapshotPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'automaticSnapshotPolicyEnabled')]" + }, + "changeFeedEnabled": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedEnabled')]" + }, + "changeFeedRetentionInDays": { + "value": "[tryGet(parameters('blobServices'), 'changeFeedRetentionInDays')]" + }, + "containerDeleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyEnabled')]" + }, + "containerDeleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyDays')]" + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'containerDeleteRetentionPolicyAllowPermanentDelete')]" + }, + "corsRules": { + "value": "[tryGet(parameters('blobServices'), 'corsRules')]" + }, + "defaultServiceVersion": { + "value": "[tryGet(parameters('blobServices'), 'defaultServiceVersion')]" + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyAllowPermanentDelete')]" + }, + "deleteRetentionPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyEnabled')]" + }, + "deleteRetentionPolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'deleteRetentionPolicyDays')]" + }, + "isVersioningEnabled": { + "value": "[tryGet(parameters('blobServices'), 'isVersioningEnabled')]" + }, + "lastAccessTimeTrackingPolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'lastAccessTimeTrackingPolicyEnabled')]" + }, + "restorePolicyEnabled": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyEnabled')]" + }, + "restorePolicyDays": { + "value": "[tryGet(parameters('blobServices'), 'restorePolicyDays')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('blobServices'), 'diagnosticSettings')]" + } + }, + "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.28.1.47646", + "templateHash": "2306287879023715578" + }, + "name": "Storage Account blob Services", + "description": "This module deploys a Storage Account Blob Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "automaticSnapshotPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Automatic Snapshot is enabled if set to true." + } + }, + "changeFeedEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for change feed events. Indicates whether change feed event logging is enabled for the Blob service." + } + }, + "changeFeedRetentionInDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 146000, + "metadata": { + "description": "Optional. Indicates whether change feed event logging is enabled for the Blob service. Indicates the duration of changeFeed retention in days. If left blank, it indicates an infinite retention of the change feed." + } + }, + "containerDeleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for container soft delete. Indicates whether DeleteRetentionPolicy is enabled." + } + }, + "containerDeleteRetentionPolicyDays": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted item should be retained." + } + }, + "containerDeleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "corsRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Specifies CORS rules for the Blob service. You can include up to five CorsRule elements in the request. If no CorsRule elements are included in the request body, all CORS rules will be deleted, and CORS will be disabled for the Blob service." + } + }, + "defaultServiceVersion": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Indicates the default version to use for requests to the Blob service if an incoming request's version is not specified. Possible values include version 2008-10-27 and all more recent versions." + } + }, + "deleteRetentionPolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. The blob service properties for blob soft delete." + } + }, + "deleteRetentionPolicyDays": { + "type": "int", + "defaultValue": 7, + "minValue": 1, + "maxValue": 365, + "metadata": { + "description": "Optional. Indicates the number of days that the deleted blob should be retained." + } + }, + "deleteRetentionPolicyAllowPermanentDelete": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This property when set to true allows deletion of the soft deleted blob versions and snapshots. This property cannot be used with blob restore policy. This property only applies to blob service and does not apply to containers or file share." + } + }, + "isVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Use versioning to automatically maintain previous versions of your blobs." + } + }, + "lastAccessTimeTrackingPolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service property to configure last access time based tracking policy. When set to true last access time based tracking is enabled." + } + }, + "restorePolicyEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The blob service properties for blob restore policy. If point-in-time restore is enabled, then versioning, change feed, and blob soft delete must also be enabled." + } + }, + "restorePolicyDays": { + "type": "int", + "defaultValue": 6, + "minValue": 1, + "metadata": { + "description": "Optional. How long this blob can be restored. It should be less than DeleteRetentionPolicy days." + } + }, + "containers": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Blob containers to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "blobServices": { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": { + "automaticSnapshotPolicyEnabled": "[parameters('automaticSnapshotPolicyEnabled')]", + "changeFeed": "[if(parameters('changeFeedEnabled'), createObject('enabled', true(), 'retentionInDays', parameters('changeFeedRetentionInDays')), null())]", + "containerDeleteRetentionPolicy": { + "enabled": "[parameters('containerDeleteRetentionPolicyEnabled')]", + "days": "[parameters('containerDeleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(equals(parameters('containerDeleteRetentionPolicyEnabled'), true()), parameters('containerDeleteRetentionPolicyAllowPermanentDelete'), null())]" + }, + "cors": { + "corsRules": "[parameters('corsRules')]" + }, + "defaultServiceVersion": "[if(not(empty(parameters('defaultServiceVersion'))), parameters('defaultServiceVersion'), null())]", + "deleteRetentionPolicy": { + "enabled": "[parameters('deleteRetentionPolicyEnabled')]", + "days": "[parameters('deleteRetentionPolicyDays')]", + "allowPermanentDelete": "[if(and(parameters('deleteRetentionPolicyEnabled'), parameters('deleteRetentionPolicyAllowPermanentDelete')), true(), null())]" + }, + "isVersioningEnabled": "[parameters('isVersioningEnabled')]", + "lastAccessTimeTrackingPolicy": "[if(not(equals(reference('storageAccount', '2022-09-01', 'full').kind, 'Storage')), createObject('enable', parameters('lastAccessTimeTrackingPolicyEnabled'), 'name', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 'AccessTimeTracking', null()), 'trackingGranularityInDays', if(equals(parameters('lastAccessTimeTrackingPolicyEnabled'), true()), 1, null())), null())]", + "restorePolicy": "[if(parameters('restorePolicyEnabled'), createObject('enabled', true(), 'days', parameters('restorePolicyDays')), null())]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "blobServices_diagnosticSettings": { + "copy": { + "name": "blobServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "blobServices" + ] + }, + "blobServices_container": { + "copy": { + "name": "blobServices_container", + "count": "[length(coalesce(parameters('containers'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Container-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" + }, + "defaultEncryptionScope": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'defaultEncryptionScope')]" + }, + "denyEncryptionScopeOverride": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'denyEncryptionScopeOverride')]" + }, + "enableNfsV3AllSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3AllSquash')]" + }, + "enableNfsV3RootSquash": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'enableNfsV3RootSquash')]" + }, + "immutableStorageWithVersioningEnabled": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutableStorageWithVersioningEnabled')]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'metadata')]" + }, + "publicAccess": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'publicAccess')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "immutabilityPolicyProperties": { + "value": "[tryGet(coalesce(parameters('containers'), createArray())[copyIndex()], 'immutabilityPolicyProperties')]" + } + }, + "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.28.1.47646", + "templateHash": "7045309160947869799" + }, + "name": "Storage Account Blob Containers", + "description": "This module deploys a Storage Account Blob Container.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage container to deploy." + } + }, + "defaultEncryptionScope": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default the container to use specified encryption scope for all writes." + } + }, + "denyEncryptionScopeOverride": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Block override of encryption scope from the container default." + } + }, + "enableNfsV3AllSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 all squash on blob container." + } + }, + "enableNfsV3RootSquash": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable NFSv3 root squash on blob container." + } + }, + "immutableStorageWithVersioningEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is an immutable property, when set to true it enables object level immutability at the container level. The property is immutable and can only be set to true at the container creation time. Existing containers must undergo a migration process." + } + }, + "immutabilityPolicyName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. Name of the immutable policy." + } + }, + "immutabilityPolicyProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configure immutability policy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. A name-value pair to associate with the container as metadata." + } + }, + "publicAccess": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "Container", + "Blob", + "None" + ], + "metadata": { + "description": "Optional. Specifies whether data in the container may be accessed publicly and the level of access." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Blob Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "Storage Blob Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "Storage Blob Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]", + "Storage Blob Delegator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db58b8e5-c6ad-4a2a-8342-4190687cbf4a')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::blobServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[parameters('storageAccountName')]" + }, + "container": { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", + "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", + "enableNfsV3AllSquash": "[if(equals(parameters('enableNfsV3AllSquash'), true()), parameters('enableNfsV3AllSquash'), null())]", + "enableNfsV3RootSquash": "[if(equals(parameters('enableNfsV3RootSquash'), true()), parameters('enableNfsV3RootSquash'), null())]", + "immutableStorageWithVersioning": "[if(equals(parameters('immutableStorageWithVersioningEnabled'), true()), createObject('enabled', parameters('immutableStorageWithVersioningEnabled')), null())]", + "metadata": "[parameters('metadata')]", + "publicAccess": "[parameters('publicAccess')]" + }, + "dependsOn": [ + "storageAccount::blobServices" + ] + }, + "container_roleAssignments": { + "copy": { + "name": "container_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', 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": [ + "container" + ] + }, + "immutabilityPolicy": { + "condition": "[not(empty(coalesce(parameters('immutabilityPolicyProperties'), createObject())))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('immutabilityPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "containerName": { + "value": "[parameters('name')]" + }, + "immutabilityPeriodSinceCreationInDays": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'immutabilityPeriodSinceCreationInDays')]" + }, + "allowProtectedAppendWrites": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWrites')]" + }, + "allowProtectedAppendWritesAll": { + "value": "[tryGet(parameters('immutabilityPolicyProperties'), 'allowProtectedAppendWritesAll')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "2543276032744560941" + }, + "name": "Storage Account Blob Container Immutability Policies", + "description": "This module deploys a Storage Account Blob Container Immutability Policy.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent container to apply the policy to. Required if the template is used in a standalone deployment." + } + }, + "immutabilityPeriodSinceCreationInDays": { + "type": "int", + "defaultValue": 365, + "metadata": { + "description": "Optional. The immutability period for the blobs in the container since the policy creation, in days." + } + }, + "allowProtectedAppendWrites": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to an append blob while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API." + } + }, + "allowProtectedAppendWritesAll": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. This property can only be changed for unlocked time-based retention policies. When enabled, new blocks can be written to both \"Append and Block Blobs\" while maintaining immutability protection and compliance. Only new blocks can be added and any existing blocks cannot be modified or deleted. This property cannot be changed with ExtendImmutabilityPolicy API. The \"allowProtectedAppendWrites\" and \"allowProtectedAppendWritesAll\" properties are mutually exclusive." + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies", + "apiVersion": "2022-09-01", + "name": "[format('{0}/{1}/{2}/{3}', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]", + "properties": { + "immutabilityPeriodSinceCreationInDays": "[parameters('immutabilityPeriodSinceCreationInDays')]", + "allowProtectedAppendWrites": "[parameters('allowProtectedAppendWrites')]", + "allowProtectedAppendWritesAll": "[parameters('allowProtectedAppendWritesAll')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed immutability policy." + }, + "value": "default" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed immutability policy." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies', parameters('storageAccountName'), 'default', parameters('containerName'), 'default')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed immutability policy." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "container", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed container." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed container." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed blob service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the deployed blob service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_fileServices": { + "condition": "[not(empty(parameters('fileServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-FileServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('fileServices'), 'diagnosticSettings')]" + }, + "protocolSettings": { + "value": "[tryGet(parameters('fileServices'), 'protocolSettings')]" + }, + "shareDeleteRetentionPolicy": { + "value": "[tryGet(parameters('fileServices'), 'shareDeleteRetentionPolicy')]" + }, + "shares": { + "value": "[tryGet(parameters('fileServices'), 'shares')]" + } + }, + "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.28.1.47646", + "templateHash": "7463227074634701879" + }, + "name": "Storage Account File Share Services", + "description": "This module deploys a Storage Account File Share Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the file service." + } + }, + "protocolSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Protocol settings for file service." + } + }, + "shareDeleteRetentionPolicy": { + "type": "object", + "defaultValue": { + "enabled": true, + "days": 7 + }, + "metadata": { + "description": "Optional. The service properties for soft delete." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "shares": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. File shares to create." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileServices": { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('name'))]", + "properties": { + "protocolSettings": "[parameters('protocolSettings')]", + "shareDeleteRetentionPolicy": "[parameters('shareDeleteRetentionPolicy')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "fileServices_diagnosticSettings": { + "copy": { + "name": "fileServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/fileServices/{1}', parameters('storageAccountName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "fileServices" + ] + }, + "fileServices_shares": { + "copy": { + "name": "fileServices_shares", + "count": "[length(coalesce(parameters('shares'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-shares-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "fileServicesName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('shares'), createArray())[copyIndex()].name]" + }, + "accessTier": { + "value": "[coalesce(tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'accessTier'), if(equals(reference('storageAccount', '2023-04-01', 'full').kind, 'FileStorage'), 'Premium', 'TransactionOptimized'))]" + }, + "enabledProtocols": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'enabledProtocols')]" + }, + "rootSquash": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'rootSquash')]" + }, + "shareQuota": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'shareQuota')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('shares'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "1342480740201032357" + }, + "name": "Storage Account File Shares", + "description": "This module deploys a Storage Account File Share.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "fileServicesName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Conditional. The name of the parent file service. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the file share to create." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "TransactionOptimized", + "allowedValues": [ + "Premium", + "Hot", + "Cool", + "TransactionOptimized" + ], + "metadata": { + "description": "Conditional. Access tier for specific share. Required if the Storage Account kind is set to FileStorage (should be set to \"Premium\"). GpV2 account can choose between TransactionOptimized (default), Hot, and Cool." + } + }, + "shareQuota": { + "type": "int", + "defaultValue": 5120, + "metadata": { + "description": "Optional. The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5120 (5TB). For Large File Shares, the maximum size is 102400 (100TB)." + } + }, + "enabledProtocols": { + "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], + "metadata": { + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } + }, + "rootSquash": { + "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], + "metadata": { + "description": "Optional. Permissions for NFS file shares are enforced by the client OS rather than the Azure Files service. Toggling the root squash behavior reduces the rights of the root user for NFS shares." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "resources": { + "storageAccount::fileService": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('fileServicesName'))]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "fileShare": { + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2023-01-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + }, + "dependsOn": [ + "storageAccount::fileService" + ] + }, + "fileShare_roleAssignments": { + "condition": "[not(empty(parameters('roleAssignments')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Share-Rbac', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "fileShareResourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "roleAssignments": { + "value": "[parameters('roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "8779226603522513073" + } + }, + "parameters": { + "roleAssignments": { + "type": "array", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "fileShareResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the file share to assign the roles to." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string", + "metadata": { + "description": "Required. The scope to deploy the role assignment to." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition Id to assign." + } + }, + "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", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "defaultValue": "", + "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" + ], + "defaultValue": "2.0", + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "description": "[[parameters('description')]", + "principalType": "[[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "condition": "[[if(not(empty(parameters('condition'))), parameters('condition'), null())]", + "conditionVersion": "[[if(and(not(empty(parameters('conditionVersion'))), not(empty(parameters('condition')))), parameters('conditionVersion'), null())]", + "delegatedManagedIdentityResourceId": "[[if(not(empty(parameters('delegatedManagedIdentityResourceId'))), parameters('delegatedManagedIdentityResourceId'), null())]" + } + } + ] + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage File Data SMB Share Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb')]", + "Storage File Data SMB Share Elevated Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7264617-510b-434b-a828-9731dc254ea7')]", + "Storage File Data SMB Share Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "fileShare_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "[format('{0}-Share-Rbac-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[replace(parameters('fileShareResourceId'), '/shares/', '/fileShares/')]" + }, + "name": { + "value": "[guid(parameters('fileShareResourceId'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, 'tyfa')]" + }, + "roleDefinitionId": { + "value": "[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": { + "value": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]" + }, + "principalType": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]" + }, + "condition": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]" + }, + "conditionVersion": { + "value": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]" + }, + "delegatedManagedIdentityResourceId": { + "value": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + } + } + } + } + ] + } + }, + "dependsOn": [ + "fileShare" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices/shares', parameters('storageAccountName'), parameters('fileServicesName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "fileServices", + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('storageAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_queueServices": { + "condition": "[not(empty(parameters('queueServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-QueueServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('queueServices'), 'diagnosticSettings')]" + }, + "queues": { + "value": "[tryGet(parameters('queueServices'), 'queues')]" + } + }, + "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.28.1.47646", + "templateHash": "10678250016540336570" + }, + "name": "Storage Account Queue Services", + "description": "This module deploys a Storage Account Queue Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "queues": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Queues to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queueServices": { + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "queueServices_diagnosticSettings": { + "copy": { + "name": "queueServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "queueServices" + ] + }, + "queueServices_queues": { + "copy": { + "name": "queueServices_queues", + "count": "[length(coalesce(parameters('queues'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Queue-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "name": { + "value": "[coalesce(parameters('queues'), createArray())[copyIndex()].name]" + }, + "metadata": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'metadata')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('queues'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "13487964166280180730" + }, + "name": "Storage Account Queues", + "description": "This module deploys a Storage Account Queue.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the storage queue to deploy." + } + }, + "metadata": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Required. A name-value pair that represents queue metadata." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Queue Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]", + "Storage Queue Data Message Processor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8a0f0c08-91a1-4084-bc3d-661d67233fed')]", + "Storage Queue Data Message Sender": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c6a89b2d-59bc-44d0-9896-0f6e12d7b80a')]", + "Storage Queue Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '19e7f393-937e-4f77-808e-94535e297925')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::queueServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/queueServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "queue": { + "type": "Microsoft.Storage/storageAccounts/queueServices/queues", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "properties": { + "metadata": "[parameters('metadata')]" + }, + "dependsOn": [ + "storageAccount::queueServices" + ] + }, + "queue_roleAssignments": { + "copy": { + "name": "queue_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/queueServices/{1}/queues/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', 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": [ + "queue" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed queue." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed queue." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices/queues', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed queue." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/queueServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount_tableServices": { + "condition": "[not(empty(parameters('tableServices')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Storage-TableServices', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('name')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('tableServices'), 'diagnosticSettings')]" + }, + "tables": { + "value": "[tryGet(parameters('tableServices'), 'tables')]" + } + }, + "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.28.1.47646", + "templateHash": "16839054392438941735" + }, + "name": "Storage Account Table Services", + "description": "This module deploys a Storage Account Table Service.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. tables to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "name": "default" + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "tableServices": { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), variables('name'))]", + "properties": {}, + "dependsOn": [ + "storageAccount" + ] + }, + "tableServices_diagnosticSettings": { + "copy": { + "name": "tableServices_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}', parameters('storageAccountName'), variables('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', variables('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "tableServices" + ] + }, + "tableServices_tables": { + "copy": { + "name": "tableServices_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Table-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "storageAccountName": { + "value": "[parameters('storageAccountName')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "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.28.1.47646", + "templateHash": "3177845984945141330" + }, + "name": "Storage Account Table", + "description": "This module deploys a Storage Account Table.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "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": { + "storageAccountName": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the table." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '81a9662b-bebf-436f-a333-f67b29880f12')]", + "Storage Table Data Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]", + "Storage Table Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76199698-9eea-4c19-bc75-cec21354c6b6')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "storageAccount::tableServices": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "dependsOn": [ + "storageAccount" + ] + }, + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-04-01", + "name": "[parameters('storageAccountName')]" + }, + "table": { + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "dependsOn": [ + "storageAccount::tableServices" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/tableServices/{1}/tables/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', 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": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed file share service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed file share service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices/tables', parameters('storageAccountName'), 'default', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed file share service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed table service." + }, + "value": "[variables('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed table service." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts/tableServices', parameters('storageAccountName'), variables('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed table service." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "storageAccount" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage account." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed storage account." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed storage account." + }, + "value": "[resourceGroup().name]" + }, + "primaryBlobEndpoint": { + "type": "string", + "metadata": { + "description": "The primary blob endpoint reference if blob services are deployed." + }, + "value": "[if(and(not(empty(parameters('blobServices'))), contains(parameters('blobServices'), 'containers')), reference(format('Microsoft.Storage/storageAccounts/{0}', parameters('name')), '2019-04-01').primaryEndpoints.blob, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "dsMsi", + "rg", + "storageFileDataPrivilegedContributorRole", + "vnet" + ] + }, + "storageAccount_upload": { + "condition": "[or(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only base')), equals(parameters('deploymentsToPerform'), 'Only assets & image'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-storage-upload-ds', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', parameters('storageDeploymentScriptName'), variables('formattedTime'))]" + }, + "kind": { + "value": "AzurePowerShell" + }, + "azPowerShellVersion": { + "value": "12.0" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('deploymentScriptManagedIdentityName'))]" + ] + } + }, + "scriptContent": { + "value": "[variables('$fxv#0')]" + }, + "environmentVariables": { + "value": "[map(coalesce(parameters('storageAccountFilesToUpload'), createArray()), lambda('file', createObject('name', format('__SCRIPT__{0}', replace(replace(lambdaVariables('file').name, '-', '__'), '.', '_')), 'value', tryGet(lambdaVariables('file'), 'value'), 'secureValue', tryGet(lambdaVariables('file'), 'secureValue'))))]" + }, + "arguments": { + "value": "[format(' -StorageAccountName \"{0}\" -TargetContainer \"{1}\"', parameters('assetsStorageAccountName'), parameters('assetsStorageAccountContainerName'))]" + }, + "timeout": { + "value": "PT30M" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageAccountResourceId": { + "value": "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Storage/storageAccounts', parameters('deploymentScriptStorageAccountName'))]" + }, + "subnetResourceIds": { + "value": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('deploymentScriptSubnetName'))]" + ] + } + }, + "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.29.47.4906", + "templateHash": "5978422939896103340" + }, + "name": "Deployment Scripts", + "description": "This module deploys Deployment Scripts.", + "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 + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "environmentVariableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Required. The value of the secure environment variable." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The value of the environment variable." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 90, + "metadata": { + "description": "Required. Name of the Deployment Script." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AzureCLI", + "AzurePowerShell" + ], + "metadata": { + "description": "Required. Specifies the Kind of the Deployment Script." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "azPowerShellVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list." + } + }, + "azCliVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list." + } + }, + "scriptContent": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead." + } + }, + "primaryScriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead." + } + }, + "environmentVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVariableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables to pass over to the script." + } + }, + "supportingScriptUris": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent)." + } + }, + "subnetResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet)." + } + }, + "arguments": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Command-line arguments to pass to the script. Arguments are separated by spaces." + } + }, + "retentionInterval": { + "type": "string", + "defaultValue": "P1D", + "metadata": { + "description": "Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week)." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed." + } + }, + "runOnce": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to false, script will run every time the template is deployed. When set to true, the script will only run once." + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "Always", + "allowedValues": [ + "Always", + "OnSuccess", + "OnExpiration" + ], + "metadata": { + "description": "Optional. The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled)." + } + }, + "containerGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed." + } + }, + "storageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account." + } + }, + "timeout": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year." + } + }, + "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." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "subnetIds", + "count": "[length(coalesce(parameters('subnetResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('subnetResourceIds'), createArray())[copyIndex('subnetIds')]]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "containerSettings": { + "containerGroupName": "[parameters('containerGroupName')]", + "subnetIds": "[if(not(empty(coalesce(variables('subnetIds'), createArray()))), variables('subnetIds'), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), 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(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "storageAccount": { + "condition": "[not(empty(parameters('storageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "subscriptionId": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "deploymentScript": { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[parameters('kind')]", + "properties": { + "azPowerShellVersion": "[if(equals(parameters('kind'), 'AzurePowerShell'), parameters('azPowerShellVersion'), null())]", + "azCliVersion": "[if(equals(parameters('kind'), 'AzureCLI'), parameters('azCliVersion'), null())]", + "containerSettings": "[if(not(empty(variables('containerSettings'))), variables('containerSettings'), null())]", + "storageAccountSettings": "[if(not(empty(parameters('storageAccountResourceId'))), if(not(empty(parameters('storageAccountResourceId'))), createObject('storageAccountKey', if(empty(parameters('subnetResourceIds')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2], split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))), '2023-01-01').keys[0].value, null()), 'storageAccountName', last(split(parameters('storageAccountResourceId'), '/'))), null()), null())]", + "arguments": "[parameters('arguments')]", + "environmentVariables": "[parameters('environmentVariables')]", + "scriptContent": "[if(not(empty(parameters('scriptContent'))), parameters('scriptContent'), null())]", + "primaryScriptUri": "[if(not(empty(parameters('primaryScriptUri'))), parameters('primaryScriptUri'), null())]", + "supportingScriptUris": "[if(not(empty(parameters('supportingScriptUris'))), parameters('supportingScriptUris'), null())]", + "cleanupPreference": "[parameters('cleanupPreference')]", + "forceUpdateTag": "[if(parameters('runOnce'), resourceGroup().name, parameters('baseTime'))]", + "retentionInterval": "[parameters('retentionInterval')]", + "timeout": "[parameters('timeout')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "deploymentScript_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.Resources/deploymentScripts/{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": [ + "deploymentScript" + ] + }, + "deploymentScript_roleAssignments": { + "copy": { + "name": "deploymentScript_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "deploymentScriptLogs": { + "existing": true, + "type": "Microsoft.Resources/deploymentScripts/logs", + "apiVersion": "2023-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "deploymentScript" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployment script." + }, + "value": "[resourceId('Microsoft.Resources/deploymentScripts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the deployment script was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployment script." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('deploymentScript', '2023-08-01', 'full').location]" + }, + "outputs": { + "type": "object", + "metadata": { + "description": "The output of the deployment script." + }, + "value": "[coalesce(tryGet(reference('deploymentScript'), 'outputs'), createObject())]" + }, + "deploymentScriptLogs": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The logs of the deployment script." + }, + "value": "[split(reference('deploymentScriptLogs').log, '\n')]" + } + } + } + }, + "dependsOn": [ + "assetsStorageAccount", + "dsMsi", + "dsStorageAccount", + "rg", + "vnet" + ] + }, + "imageTemplate": { + "condition": "[or(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only assets & image')), equals(parameters('deploymentsToPerform'), 'Only image'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-it', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "customizationSteps": { + "value": "[parameters('imageTemplateCustomizationSteps')]" + }, + "imageSource": { + "value": "[parameters('imageTemplateImageSource')]" + }, + "name": { + "value": "[parameters('imageTemplateName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('imageManagedIdentityName'))]" + ] + } + }, + "distributions": { + "value": [ + { + "type": "SharedImage", + "sharedImageGalleryImageDefinitionResourceId": "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Compute/galleries/images', parameters('computeGalleryName'), parameters('computeGalleryImageDefinitionName'))]" + } + ] + }, + "subnetResourceId": { + "value": "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('imageSubnetName'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "stagingResourceGroupResourceId": { + "value": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('imageTemplateResourceGroupName'))]" + }, + "roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Contributor", + "principalId": "[if(or(equals(parameters('deploymentsToPerform'), 'Only assets & image'), equals(parameters('deploymentsToPerform'), 'Only image')), reference('dsMsi_existing').principalId, reference('dsMsi').outputs.principalId.value)]", + "principalType": "ServicePrincipal" + } + ] + } + }, + "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.29.47.4906", + "templateHash": "18298474056790033884" + }, + "name": "Virtual Machine Image Templates", + "description": "This module deploys a Virtual Machine Image Template that can be consumed by Azure Image Builder (AIB).", + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + } + }, + "distributionType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "SharedImage": { + "$ref": "#/definitions/sharedImageDistributionType" + }, + "ManagedImage": { + "$ref": "#/definitions/managedImageDistributionType" + }, + "VHD": { + "$ref": "#/definitions/unManagedDistributionType" + } + } + } + }, + "sharedImageDistributionType": { + "type": "object", + "properties": { + "runOutputName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated." + } + }, + "artifactTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "SharedImage" + ], + "metadata": { + "description": "Required. The type of distribution." + } + }, + "sharedImageGalleryImageDefinitionResourceId": { + "type": "string", + "metadata": { + "description": "Conditional. Resource ID of Compute Gallery Image Definition to distribute image to, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Compute/galleries//images/." + } + }, + "sharedImageGalleryImageDefinitionTargetVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Version of the Compute Gallery Image. Supports the following Version Syntax: Major.Minor.Build (i.e., '1.1.1' or '10.1.2'). If not provided, a version will be calculated." + } + }, + "excludeFromLatest": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The exclude from latest flag of the image. Defaults to [false]." + } + }, + "replicationRegions": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The replication regions of the image. Defaults to the value of the 'location' parameter." + } + }, + "storageAccountType": { + "type": "string", + "allowedValues": [ + "Standard_LRS", + "Standard_ZRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. The storage account type of the image. Defaults to [Standard_LRS]." + } + } + } + }, + "unManagedDistributionType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "VHD" + ], + "metadata": { + "description": "Required. The type of distribution." + } + }, + "runOutputName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated." + } + }, + "artifactTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source." + } + }, + "imageName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the managed or unmanaged image that will be created." + } + } + } + }, + "managedImageDistributionType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "ManagedImage" + ], + "metadata": { + "description": "Required. The type of distribution." + } + }, + "runOutputName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to be used for the associated RunOutput. If not provided, a name will be calculated." + } + }, + "artifactTags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags that will be applied to the artifact once it has been created/updated by the distributor. If not provided will set tags based on the provided image source." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure location for the image, should match if image already exists. Defaults to the value of the 'location' parameter." + } + }, + "imageResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The resource ID of the managed image. Defaults to a compute image with name 'imageName-baseTime' in the current resource group." + } + }, + "imageName": { + "type": "string", + "metadata": { + "description": "Conditional. Name of the managed or unmanaged image that will be created." + } + } + } + }, + "validationProcessType": { + "type": "object", + "properties": { + "continueDistributeOnFailure": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If validation fails and this field is set to false, output image(s) will not be distributed. This is the default behavior. If validation fails and this field is set to true, output image(s) will still be distributed. Please use this option with caution as it may result in bad images being distributed for use. In either case (true or false), the end to end image run will be reported as having failed in case of a validation failure. [Note: This field has no effect if validation succeeds.]." + } + }, + "inVMValidations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "File", + "PowerShell", + "Shell" + ], + "metadata": { + "description": "Required. The type of validation." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Friendly Name to provide context on what this validation step does." + } + }, + "scriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URI of the PowerShell script to be run for validation. It can be a github link, Azure Storage URI, etc." + } + }, + "inline": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of commands to be run, separated by commas." + } + }, + "validExitCodes": { + "type": "array", + "items": { + "type": "int" + }, + "nullable": true, + "metadata": { + "description": "Optional. Valid codes that can be returned from the script/inline command, this avoids reported failure of the script/inline command." + } + }, + "sha256Checksum": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value of sha256 checksum of the file, you generate this locally, and then Image Builder will checksum and validate." + } + }, + "sourceUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source URI of the file." + } + }, + "destination": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Destination of the file." + } + }, + "runAsSystem": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If specified, the PowerShell script will be run with elevated privileges using the Local System user. Can only be true when the runElevated field above is set to true." + } + }, + "runElevated": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If specified, the PowerShell script will be run with elevated privileges." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of validators that will be performed on the image. Azure Image Builder supports File, PowerShell and Shell validators." + } + }, + "sourceValidationOnly": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If this field is set to true, the image specified in the 'source' section will directly be validated. No separate build will be run to generate and then validate a customized image. Not supported when performing customizations, validations or distributions on the image." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name prefix of the Image Template to be built by the Azure Image Builder service." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "buildTimeoutInMinutes": { + "type": "int", + "defaultValue": 0, + "minValue": 0, + "maxValue": 960, + "metadata": { + "description": "Optional. The image build timeout in minutes. 0 means the default 240 minutes." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D2s_v3", + "metadata": { + "description": "Optional. Specifies the size for the VM." + } + }, + "osDiskSizeGB": { + "type": "int", + "defaultValue": 128, + "metadata": { + "description": "Optional. Specifies the size of OS disk." + } + }, + "subnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of an already existing subnet, e.g.: /subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/.

    If no value is provided, a new temporary VNET and subnet will be created in the staging resource group and will be deleted along with the remaining temporary resources." + } + }, + "imageSource": { + "type": "object", + "metadata": { + "description": "Required. Image source definition in object format." + } + }, + "customizationSteps": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Customization steps to be run when building the VM image." + } + }, + "stagingResourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the staging resource group in the same subscription and location as the image template that will be used to build the image.

    If this field is empty, a resource group with a random name will be created.

    If the resource group specified in this field doesn't exist, it will be created with the same name.

    If the resource group specified exists, it must be empty and in the same region as the image template.

    The resource group created will be deleted during template deletion if this field is empty or the resource group specified doesn't exist,

    but if the resource group specified exists the resources created in the resource group will be deleted during template deletion and the resource group itself will remain." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to generate a unique image template name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "distributions": { + "type": "array", + "items": { + "$ref": "#/definitions/distributionType" + }, + "metadata": { + "description": "Required. The distribution targets where the image output needs to go to." + } + }, + "vmUserAssignedIdentities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of User-Assigned Identities associated to the Build VM for accessing Azure resources such as Key Vaults from your customizer scripts. Be aware, the user assigned identities specified in the 'managedIdentities' parameter must have the 'Managed Identity Operator' role assignment on all the user assigned identities specified in this parameter for Azure Image Builder to be able to associate them to the build VM." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "validationProcess": { + "$ref": "#/definitions/validationProcessType", + "metadata": { + "description": "Optional. Configuration options and list of validations to be performed on the resulting image." + } + }, + "optimizeVmBoot": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The optimize property can be enabled while creating a VM image and allows VM optimization to improve image creation time." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": "[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'))))]" + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.virtualmachineimages-imagetemplate.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "imageTemplate": { + "type": "Microsoft.VirtualMachineImages/imageTemplates", + "apiVersion": "2023-07-01", + "name": "[format('{0}-{1}', parameters('name'), parameters('baseTime'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "copy": [ + { + "name": "distribute", + "count": "[length(parameters('distributions'))]", + "input": "[union(createObject('type', parameters('distributions')[copyIndex('distribute')].type, 'artifactTags', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'artifactTags'), createObject('sourceType', parameters('imageSource').type, 'sourcePublisher', tryGet(parameters('imageSource'), 'publisher'), 'sourceOffer', tryGet(parameters('imageSource'), 'offer'), 'sourceSku', tryGet(parameters('imageSource'), 'sku'), 'sourceVersion', tryGet(parameters('imageSource'), 'version'), 'sourceImageId', tryGet(parameters('imageSource'), 'imageId'), 'sourceImageVersionID', tryGet(parameters('imageSource'), 'imageVersionID'), 'creationTime', parameters('baseTime')))), if(equals(parameters('distributions')[copyIndex('distribute')].type, 'ManagedImage'), createObject('runOutputName', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'runOutputName'), format('{0}-{1}-ManagedImage', parameters('distributions')[copyIndex('distribute')].imageName, parameters('baseTime'))), 'location', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'location'), parameters('location')), 'imageId', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'imageResourceId'), format('{0}/resourceGroups/{1}/providers/Microsoft.Compute/images/{2}-{3}', subscription().id, resourceGroup().name, parameters('distributions')[copyIndex('distribute')].imageName, parameters('baseTime')))), createObject()), if(equals(parameters('distributions')[copyIndex('distribute')].type, 'SharedImage'), createObject('runOutputName', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'runOutputName'), if(not(empty(tryGet(parameters('distributions')[copyIndex('distribute')], 'sharedImageGalleryImageDefinitionResourceId'))), format('{0}-SharedImage', last(split(coalesce(parameters('distributions')[copyIndex('distribute')].sharedImageGalleryImageDefinitionResourceId, '/'), '/'))), 'SharedImage')), 'galleryImageId', if(not(empty(tryGet(parameters('distributions')[copyIndex('distribute')], 'sharedImageGalleryImageDefinitionTargetVersion'))), format('{0}/versions/{1}', parameters('distributions')[copyIndex('distribute')].sharedImageGalleryImageDefinitionResourceId, parameters('distributions')[copyIndex('distribute')].sharedImageGalleryImageDefinitionTargetVersion), parameters('distributions')[copyIndex('distribute')].sharedImageGalleryImageDefinitionResourceId), 'excludeFromLatest', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'excludeFromLatest'), false()), 'replicationRegions', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'replicationRegions'), createArray(parameters('location'))), 'storageAccountType', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'storageAccountType'), 'Standard_LRS')), createObject()), if(equals(parameters('distributions')[copyIndex('distribute')].type, 'VHD'), createObject('runOutputName', coalesce(tryGet(parameters('distributions')[copyIndex('distribute')], 'runOutputName'), format('{0}-VHD', parameters('distributions')[copyIndex('distribute')].imageName))), createObject()))]" + } + ], + "buildTimeoutInMinutes": "[parameters('buildTimeoutInMinutes')]", + "vmProfile": { + "vmSize": "[parameters('vmSize')]", + "osDiskSizeGB": "[parameters('osDiskSizeGB')]", + "userAssignedIdentities": "[parameters('vmUserAssignedIdentities')]", + "vnetConfig": "[if(not(empty(parameters('subnetResourceId'))), createObject('subnetId', parameters('subnetResourceId')), null())]" + }, + "source": "[parameters('imageSource')]", + "customize": "[parameters('customizationSteps')]", + "stagingResourceGroup": "[parameters('stagingResourceGroupResourceId')]", + "validate": "[parameters('validationProcess')]", + "optimize": "[if(not(equals(parameters('optimizeVmBoot'), null())), createObject('vmBoot', createObject('state', parameters('optimizeVmBoot'))), null())]" + } + }, + "imageTemplate_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.VirtualMachineImages/imageTemplates/{0}', format('{0}-{1}', parameters('name'), parameters('baseTime')))]", + "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": [ + "imageTemplate" + ] + }, + "imageTemplate_roleAssignments": { + "copy": { + "name": "imageTemplate_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.VirtualMachineImages/imageTemplates/{0}', format('{0}-{1}', parameters('name'), parameters('baseTime')))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.VirtualMachineImages/imageTemplates', format('{0}-{1}', parameters('name'), parameters('baseTime'))), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "imageTemplate" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the image template." + }, + "value": "[resourceId('Microsoft.VirtualMachineImages/imageTemplates', format('{0}-{1}', parameters('name'), parameters('baseTime')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the image template was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The full name of the deployed image template." + }, + "value": "[format('{0}-{1}', parameters('name'), parameters('baseTime'))]" + }, + "namePrefix": { + "type": "string", + "metadata": { + "description": "The prefix of the image template name provided as input." + }, + "value": "[parameters('name')]" + }, + "runThisCommand": { + "type": "string", + "metadata": { + "description": "The command to run in order to trigger the image build." + }, + "value": "[format('Invoke-AzResourceAction -ResourceName {0} -ResourceGroupName {1} -ResourceType Microsoft.VirtualMachineImages/imageTemplates -Action Run -Force', format('{0}-{1}', parameters('name'), parameters('baseTime')), resourceGroup().name)]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('imageTemplate', '2023-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "azureComputeGallery", + "dsMsi", + "dsMsi_existing", + "imageMSI", + "imageMSI_rbac", + "imageTemplateRg", + "rg", + "storageAccount_upload", + "vnet" + ] + }, + "imageTemplate_trigger": { + "condition": "[or(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only assets & image')), equals(parameters('deploymentsToPerform'), 'Only image'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-imageTemplate-trigger-ds', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}-{2}', parameters('imageTemplateDeploymentScriptName'), variables('formattedTime'), if(or(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only assets & image')), equals(parameters('deploymentsToPerform'), 'Only image')), reference('imageTemplate').outputs.name.value, ''))]" + }, + "kind": { + "value": "AzurePowerShell" + }, + "azPowerShellVersion": { + "value": "12.0" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('deploymentScriptManagedIdentityName'))]" + ] + } + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "scriptContent": "[if(or(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only assets & image')), equals(parameters('deploymentsToPerform'), 'Only image')), createObject('value', reference('imageTemplate').outputs.runThisCommand.value), createObject('value', ''))]", + "timeout": { + "value": "PT30M" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageAccountResourceId": { + "value": "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Storage/storageAccounts', parameters('deploymentScriptStorageAccountName'))]" + }, + "subnetResourceIds": { + "value": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('deploymentScriptSubnetName'))]" + ] + } + }, + "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.29.47.4906", + "templateHash": "5978422939896103340" + }, + "name": "Deployment Scripts", + "description": "This module deploys Deployment Scripts.", + "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 + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "environmentVariableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Required. The value of the secure environment variable." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The value of the environment variable." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 90, + "metadata": { + "description": "Required. Name of the Deployment Script." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AzureCLI", + "AzurePowerShell" + ], + "metadata": { + "description": "Required. Specifies the Kind of the Deployment Script." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "azPowerShellVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list." + } + }, + "azCliVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list." + } + }, + "scriptContent": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead." + } + }, + "primaryScriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead." + } + }, + "environmentVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVariableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables to pass over to the script." + } + }, + "supportingScriptUris": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent)." + } + }, + "subnetResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet)." + } + }, + "arguments": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Command-line arguments to pass to the script. Arguments are separated by spaces." + } + }, + "retentionInterval": { + "type": "string", + "defaultValue": "P1D", + "metadata": { + "description": "Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week)." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed." + } + }, + "runOnce": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to false, script will run every time the template is deployed. When set to true, the script will only run once." + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "Always", + "allowedValues": [ + "Always", + "OnSuccess", + "OnExpiration" + ], + "metadata": { + "description": "Optional. The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled)." + } + }, + "containerGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed." + } + }, + "storageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account." + } + }, + "timeout": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year." + } + }, + "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." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "subnetIds", + "count": "[length(coalesce(parameters('subnetResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('subnetResourceIds'), createArray())[copyIndex('subnetIds')]]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "containerSettings": { + "containerGroupName": "[parameters('containerGroupName')]", + "subnetIds": "[if(not(empty(coalesce(variables('subnetIds'), createArray()))), variables('subnetIds'), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), 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(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "storageAccount": { + "condition": "[not(empty(parameters('storageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "subscriptionId": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "deploymentScript": { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[parameters('kind')]", + "properties": { + "azPowerShellVersion": "[if(equals(parameters('kind'), 'AzurePowerShell'), parameters('azPowerShellVersion'), null())]", + "azCliVersion": "[if(equals(parameters('kind'), 'AzureCLI'), parameters('azCliVersion'), null())]", + "containerSettings": "[if(not(empty(variables('containerSettings'))), variables('containerSettings'), null())]", + "storageAccountSettings": "[if(not(empty(parameters('storageAccountResourceId'))), if(not(empty(parameters('storageAccountResourceId'))), createObject('storageAccountKey', if(empty(parameters('subnetResourceIds')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2], split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))), '2023-01-01').keys[0].value, null()), 'storageAccountName', last(split(parameters('storageAccountResourceId'), '/'))), null()), null())]", + "arguments": "[parameters('arguments')]", + "environmentVariables": "[parameters('environmentVariables')]", + "scriptContent": "[if(not(empty(parameters('scriptContent'))), parameters('scriptContent'), null())]", + "primaryScriptUri": "[if(not(empty(parameters('primaryScriptUri'))), parameters('primaryScriptUri'), null())]", + "supportingScriptUris": "[if(not(empty(parameters('supportingScriptUris'))), parameters('supportingScriptUris'), null())]", + "cleanupPreference": "[parameters('cleanupPreference')]", + "forceUpdateTag": "[if(parameters('runOnce'), resourceGroup().name, parameters('baseTime'))]", + "retentionInterval": "[parameters('retentionInterval')]", + "timeout": "[parameters('timeout')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "deploymentScript_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.Resources/deploymentScripts/{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": [ + "deploymentScript" + ] + }, + "deploymentScript_roleAssignments": { + "copy": { + "name": "deploymentScript_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "deploymentScriptLogs": { + "existing": true, + "type": "Microsoft.Resources/deploymentScripts/logs", + "apiVersion": "2023-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "deploymentScript" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployment script." + }, + "value": "[resourceId('Microsoft.Resources/deploymentScripts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the deployment script was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployment script." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('deploymentScript', '2023-08-01', 'full').location]" + }, + "outputs": { + "type": "object", + "metadata": { + "description": "The output of the deployment script." + }, + "value": "[coalesce(tryGet(reference('deploymentScript'), 'outputs'), createObject())]" + }, + "deploymentScriptLogs": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The logs of the deployment script." + }, + "value": "[split(reference('deploymentScriptLogs').log, '\n')]" + } + } + } + }, + "dependsOn": [ + "dsMsi", + "dsStorageAccount", + "imageTemplate", + "rg", + "storageAccount_upload", + "vnet" + ] + }, + "imageTemplate_wait": { + "condition": "[and(parameters('waitForImageBuild'), or(or(equals(parameters('deploymentsToPerform'), 'All'), equals(parameters('deploymentsToPerform'), 'Only assets & image')), equals(parameters('deploymentsToPerform'), 'Only image')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-imageTemplate-wait-ds', deployment().name)]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-{1}', parameters('waitDeploymentScriptName'), variables('formattedTime'))]" + }, + "kind": { + "value": "AzurePowerShell" + }, + "azPowerShellVersion": { + "value": "12.0" + }, + "managedIdentities": { + "value": { + "userAssignedResourcesIds": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('deploymentScriptManagedIdentityName'))]" + ] + } + }, + "scriptContent": { + "value": "[variables('$fxv#1')]" + }, + "arguments": { + "value": "[format(' -ImageTemplateName \"{0}\" -ResourceGroupName \"{1}\"', reference('imageTemplate').outputs.name.value, parameters('resourceGroupName'))]" + }, + "timeout": { + "value": "[parameters('waitForImageBuildTimeout')]" + }, + "cleanupPreference": { + "value": "Always" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageAccountResourceId": { + "value": "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Storage/storageAccounts', parameters('deploymentScriptStorageAccountName'))]" + }, + "subnetResourceIds": { + "value": [ + "[resourceId(subscription().subscriptionId, parameters('resourceGroupName'), 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('deploymentScriptSubnetName'))]" + ] + } + }, + "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.29.47.4906", + "templateHash": "5978422939896103340" + }, + "name": "Deployment Scripts", + "description": "This module deploys Deployment Scripts.", + "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 + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "environmentVariableType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the environment variable." + } + }, + "secureValue": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Required. The value of the secure environment variable." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The value of the environment variable." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 90, + "metadata": { + "description": "Required. Name of the Deployment Script." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "AzureCLI", + "AzurePowerShell" + ], + "metadata": { + "description": "Required. Specifies the Kind of the Deployment Script." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "azPowerShellVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure PowerShell module version to be used. See a list of supported Azure PowerShell versions: https://mcr.microsoft.com/v2/azuredeploymentscripts-powershell/tags/list." + } + }, + "azCliVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Azure CLI module version to be used. See a list of supported Azure CLI versions: https://mcr.microsoft.com/v2/azure-cli/tags/list." + } + }, + "scriptContent": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Script body. Max length: 32000 characters. To run an external script, use primaryScriptURI instead." + } + }, + "primaryScriptUri": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Uri for the external script. This is the entry point for the external script. To run an internal script, use the scriptContent parameter instead." + } + }, + "environmentVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVariableType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables to pass over to the script." + } + }, + "supportingScriptUris": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. List of supporting files for the external script (defined in primaryScriptUri). Does not work with internal scripts (code defined in scriptContent)." + } + }, + "subnetResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of subnet IDs to use for the container group. This is required if you want to run the deployment script in a private network. When using a private network, the `Storage File Data Privileged Contributor` role needs to be assigned to the user-assigned managed identity and the deployment principal needs to have permissions to list the storage account keys. Also, Shared-Keys must not be disabled on the used storage account [ref](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-vnet)." + } + }, + "arguments": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Command-line arguments to pass to the script. Arguments are separated by spaces." + } + }, + "retentionInterval": { + "type": "string", + "defaultValue": "P1D", + "metadata": { + "description": "Optional. Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. Duration is based on ISO 8601 pattern (for example P7D means one week)." + } + }, + "baseTime": { + "type": "string", + "defaultValue": "[utcNow('yyyy-MM-dd-HH-mm-ss')]", + "metadata": { + "description": "Generated. Do not provide a value! This date value is used to make sure the script run every time the template is deployed." + } + }, + "runOnce": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. When set to false, script will run every time the template is deployed. When set to true, the script will only run once." + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "Always", + "allowedValues": [ + "Always", + "OnSuccess", + "OnExpiration" + ], + "metadata": { + "description": "Optional. The clean up preference when the script execution gets in a terminal state. Specify the preference on when to delete the deployment script resources. The default value is Always, which means the deployment script resources are deleted despite the terminal state (Succeeded, Failed, canceled)." + } + }, + "containerGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Container group name, if not specified then the name will get auto-generated. Not specifying a 'containerGroupName' indicates the system to generate a unique name which might end up flagging an Azure Policy as non-compliant. Use 'containerGroupName' when you have an Azure Policy that expects a specific naming convention or when you want to fully control the name. 'containerGroupName' property must be between 1 and 63 characters long, must contain only lowercase letters, numbers, and dashes and it cannot start or end with a dash and consecutive dashes are not allowed." + } + }, + "storageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the storage account to use for this deployment script. If none is provided, the deployment script uses a temporary, managed storage account." + } + }, + "timeout": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Maximum allowed script execution time specified in ISO 8601 format. Default value is PT1H - 1 hour; 'PT30M' - 30 minutes; 'P5D' - 5 days; 'P1Y' 1 year." + } + }, + "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." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "subnetIds", + "count": "[length(coalesce(parameters('subnetResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('subnetResourceIds'), createArray())[copyIndex('subnetIds')]]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "containerSettings": { + "containerGroupName": "[parameters('containerGroupName')]", + "subnetIds": "[if(not(empty(coalesce(variables('subnetIds'), createArray()))), variables('subnetIds'), null())]" + }, + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), 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(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null()), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "storageAccount": { + "condition": "[not(empty(parameters('storageAccountResourceId')))]", + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-04-01", + "subscriptionId": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]]", + "name": "[last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.resources-deploymentscript.{0}.{1}', replace('0.4.0', '.', '-'), 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" + } + } + } + } + }, + "deploymentScript": { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "kind": "[parameters('kind')]", + "properties": { + "azPowerShellVersion": "[if(equals(parameters('kind'), 'AzurePowerShell'), parameters('azPowerShellVersion'), null())]", + "azCliVersion": "[if(equals(parameters('kind'), 'AzureCLI'), parameters('azCliVersion'), null())]", + "containerSettings": "[if(not(empty(variables('containerSettings'))), variables('containerSettings'), null())]", + "storageAccountSettings": "[if(not(empty(parameters('storageAccountResourceId'))), if(not(empty(parameters('storageAccountResourceId'))), createObject('storageAccountKey', if(empty(parameters('subnetResourceIds')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '//'), '/')[2], split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(if(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountResourceId'), 'dummyAccount'), '/'))), '2023-01-01').keys[0].value, null()), 'storageAccountName', last(split(parameters('storageAccountResourceId'), '/'))), null()), null())]", + "arguments": "[parameters('arguments')]", + "environmentVariables": "[parameters('environmentVariables')]", + "scriptContent": "[if(not(empty(parameters('scriptContent'))), parameters('scriptContent'), null())]", + "primaryScriptUri": "[if(not(empty(parameters('primaryScriptUri'))), parameters('primaryScriptUri'), null())]", + "supportingScriptUris": "[if(not(empty(parameters('supportingScriptUris'))), parameters('supportingScriptUris'), null())]", + "cleanupPreference": "[parameters('cleanupPreference')]", + "forceUpdateTag": "[if(parameters('runOnce'), resourceGroup().name, parameters('baseTime'))]", + "retentionInterval": "[parameters('retentionInterval')]", + "timeout": "[parameters('timeout')]" + }, + "dependsOn": [ + "storageAccount" + ] + }, + "deploymentScript_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.Resources/deploymentScripts/{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": [ + "deploymentScript" + ] + }, + "deploymentScript_roleAssignments": { + "copy": { + "name": "deploymentScript_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Resources/deploymentScripts/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Resources/deploymentScripts', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "deploymentScript" + ] + }, + "deploymentScriptLogs": { + "existing": true, + "type": "Microsoft.Resources/deploymentScripts/logs", + "apiVersion": "2023-08-01", + "name": "[format('{0}/{1}', parameters('name'), 'default')]", + "dependsOn": [ + "deploymentScript" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployment script." + }, + "value": "[resourceId('Microsoft.Resources/deploymentScripts', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the deployment script was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployment script." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('deploymentScript', '2023-08-01', 'full').location]" + }, + "outputs": { + "type": "object", + "metadata": { + "description": "The output of the deployment script." + }, + "value": "[coalesce(tryGet(reference('deploymentScript'), 'outputs'), createObject())]" + }, + "deploymentScriptLogs": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The logs of the deployment script." + }, + "value": "[split(reference('deploymentScriptLogs').log, '\n')]" + } + } + } + }, + "dependsOn": [ + "dsMsi", + "dsStorageAccount", + "imageTemplate", + "imageTemplate_trigger", + "rg", + "vnet" + ] + } + } +} \ No newline at end of file diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/AzureComputeGalleries.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/AzureComputeGalleries.svg new file mode 100644 index 0000000000..f6b1879361 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/AzureComputeGalleries.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Deployment-Script.png b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Deployment-Script.png new file mode 100644 index 0000000000..e453471d13 Binary files /dev/null and b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Deployment-Script.png differ diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/ImageTemplates.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/ImageTemplates.svg new file mode 100644 index 0000000000..02c7715cf1 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/ImageTemplates.svg @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Managed-identities.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Managed-identities.svg new file mode 100644 index 0000000000..de5e4f48a3 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Managed-identities.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + Icon-identity-227 + + + + + + + + + + + + + + + + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Network-Security-Groups.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Network-Security-Groups.svg new file mode 100644 index 0000000000..a55b053a8a --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Network-Security-Groups.svg @@ -0,0 +1,9 @@ +Icon-networking-67 + + + public:true + sdk:false + category: Networking + + + \ No newline at end of file diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Resource-Groups.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Resource-Groups.svg new file mode 100644 index 0000000000..c99d7b5952 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Resource-Groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Storage-Accounts.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Storage-Accounts.svg new file mode 100644 index 0000000000..2fc8eb6c52 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Storage-Accounts.svg @@ -0,0 +1,22 @@ + + + + + + + + + Icon-storage-86 + + + + + + + + public:true + sdk:MsPortalFx.Base.Images.Polychromatic.Storage() + category: Storage + + + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/VMImageDefinitions.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/VMImageDefinitions.svg new file mode 100644 index 0000000000..908c8d7084 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/VMImageDefinitions.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/VMImageVersions.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/VMImageVersions.svg new file mode 100644 index 0000000000..a93a8aafa3 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/VMImageVersions.svg @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Δ + + + + + + + + + + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Virtual-Machine-Scale-Sets.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Virtual-Machine-Scale-Sets.svg new file mode 100644 index 0000000000..90fea8cf2c --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Virtual-Machine-Scale-Sets.svg @@ -0,0 +1,9 @@ +Icon-compute-34 + + + public:true + sdk:false + category: Compute + + + \ No newline at end of file diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Virtual-Networks.svg b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Virtual-Networks.svg new file mode 100644 index 0000000000..e2d8868d8a --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/src/icons/Virtual-Networks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/src/image/imageBuilderimage.png b/avm/ptn/virtual-machine-images/azure-image-builder/src/image/imageBuilderimage.png new file mode 100644 index 0000000000..23fcca251b Binary files /dev/null and b/avm/ptn/virtual-machine-images/azure-image-builder/src/image/imageBuilderimage.png differ diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..26d33bbc33 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Using small parameter set' +metadata description = 'This instance deploys the module with min features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.azureimagebuilder-${serviceShort}-rg' + +@description('Optional. The location to deploy resource group to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apvmiaibmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +///////////////////////////// +// Template Deployment // +///////////////////////////// +var computeGalleryImageDefinitionName = 'sid-linux' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + deploymentsToPerform: iteration == 'init' ? 'All' : 'Only base' // Restricting to only infra on re-run as we don't want to back 2 images but only test idempotency + resourceGroupName: resourceGroupName + location: resourceLocation + computeGalleryName: 'gal${namePrefix}${serviceShort}' + computeGalleryImageDefinitionName: computeGalleryImageDefinitionName + assetsStorageAccountName: 'st${namePrefix}${serviceShort}' + computeGalleryImageDefinitions: [ + { + hyperVGeneration: 'V2' + name: 'sid-linux' + osType: 'Linux' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' + } + ] + imageTemplateImageSource: { + type: 'PlatformImage' + publisher: 'canonical' + offer: 'ubuntu-24_04-lts' + sku: 'server' + version: 'latest' + } + } + } +] diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep new file mode 100644 index 0000000000..e6c00b9003 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/main.test.bicep @@ -0,0 +1,139 @@ +targetScope = 'subscription' + +metadata name = 'Deploying all resources' +metadata description = 'This instance deploys the module with the conditions set up to deploy all resource and build the image.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.azureimagebuilder-${serviceShort}-rg' + +@description('Optional. The location to deploy resource group to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apvmiaiba' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +///////////////////////////// +// Template Deployment // +///////////////////////////// +var computeGalleryImageDefinitionName = 'sid-linux' +var assetsStorageAccountName = 'st${namePrefix}${serviceShort}' +var assetsStorageAccountContainerName = 'aibscripts' +var installPwshScriptName = 'Install-LinuxPowerShell.sh' +var initializeSoftwareScriptName = 'Initialize-LinuxSoftware.ps1' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + deploymentsToPerform: iteration == 'init' ? 'All' : 'Only base' // Restricting to only infra on re-run as we don't want to back 2 images but only test idempotency + resourceGroupName: resourceGroupName + location: resourceLocation + assetsStorageAccountName: assetsStorageAccountName + assetsStorageAccountContainerName: assetsStorageAccountContainerName + computeGalleryName: 'gal${namePrefix}${serviceShort}' + computeGalleryImageDefinitionName: computeGalleryImageDefinitionName + computeGalleryImageDefinitions: [ + { + hyperVGeneration: 'V2' + name: computeGalleryImageDefinitionName + osType: 'Linux' + osState: 'Generalized' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + } + ] + storageAccountFilesToUpload: [ + { + name: installPwshScriptName + value: loadTextContent('scripts/${installPwshScriptName}') + } + { + name: initializeSoftwareScriptName + value: loadTextContent('scripts/${initializeSoftwareScriptName}') + } + ] + imageTemplateImageSource: { + type: 'PlatformImage' + publisher: 'canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + imageTemplateCustomizationSteps: [ + { + type: 'Shell' + name: 'PowerShell installation' + scriptUri: 'https://${assetsStorageAccountName}.blob.${environment().suffixes.storage}/${assetsStorageAccountContainerName}/${installPwshScriptName}' + } + { + type: 'File' + name: 'Download ${initializeSoftwareScriptName}' + sourceUri: 'https://${assetsStorageAccountName}.blob.${environment().suffixes.storage}/${assetsStorageAccountContainerName}/${initializeSoftwareScriptName}' + destination: initializeSoftwareScriptName + } + { + type: 'Shell' + name: 'Software installation' + inline: [ + 'pwsh \'${initializeSoftwareScriptName}\'' + ] + } + ] + + // Windoes example + // var installPwshScriptName = 'Install-WindowsPowerShell.ps1' + // var initializeSoftwareScriptName = 'Initialize-WindowsSoftware.ps1' + // computeGalleryImageDefinitions: [ + // { + // hyperVGeneration: 'V2' + // name: 'sid-windows' + // osType: 'Windows' + // publisher: 'devops' + // offer: 'devops_windows' + // sku: 'devops_windows_az' + // } + // ] + // imageTemplateImageSource: { + // type: 'PlatformImage' + // publisher: 'microsoftwindowsdesktop' + // offer: 'windows-11' + // sku: 'win11-23h2-pro' + // version: 'latest' + // } + // imageTemplateCustomizationSteps: [ + // { + // type: 'PowerShell' + // name: 'PowerShell installation' + // scriptUri: 'https://${assetsStorageAccountName}.blob.${environment().suffixes.storage}/${assetsStorageAccountContainerName}/${installPwshScriptName}' + // runElevated: true + // } + // { + // type: 'File' + // name: 'Download ${initializeSoftwareScriptName}' + // sourceUri: 'https://${assetsStorageAccountName}.blob.${environment().suffixes.storage}/${assetsStorageAccountContainerName}/${initializeSoftwareScriptName}' + // destination: initializeSoftwareScriptName + // } + // { + // type: 'PowerShell' + // name: 'Software installation' + // inline: [ + // 'pwsh \'${initializeSoftwareScriptName}\'' + // ] + // runElevated: true + // } + // ] + } + } +] diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Initialize-LinuxSoftware.ps1 b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Initialize-LinuxSoftware.ps1 new file mode 100644 index 0000000000..ace80ec04c --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Initialize-LinuxSoftware.ps1 @@ -0,0 +1,538 @@ +#region Functions +function LogInfo($message) { + Log 'Info' $message +} +function LogError($message) { + Log 'Error' $message +} +function LogWarning($message) { + Log 'Warning' $message +} + +function Log { + + <# + .SYNOPSIS + Creates a log file and stores logs based on categories with tab seperation + + .PARAMETER category + Category to put into the trace + + .PARAMETER message + Message to be loged + + .EXAMPLE + Log 'Info' 'Message' + + #> + + Param ( + [Parameter(Mandatory = $false)] + [string] $category = 'Info', + + [Parameter(Mandatory = $true)] + [string] $message + ) + + $date = Get-Date + $content = "[$date]`t$category`t`t$message`n" + Write-Verbose $Content -Verbose + + $FilePath = Join-Path ([System.IO.Path]::GetTempPath()) 'log.log' + if (-not (Test-Path $FilePath)) { + Write-Verbose "Log file not found, create new in path: [$FilePath]" -Verbose + $null = New-Item -ItemType 'File' -Path $FilePath -Force + } + Add-Content -Path $FilePath -Value $content -ErrorAction 'Stop' +} + +function Copy-FileAndFolderList { + + param( + [string] $sourcePath, + [string] $targetPath + ) + + $itemsFrom = Get-ChildItem $sourcePath + foreach ($item in $itemsFrom) { + if ($item.PSIsContainer) { + $subsourcePath = $sourcePath + '\' + $item.BaseName + $subtargetPath = $targetPath + '\' + $item.BaseName + $null = Copy-FileAndFolderList -sourcePath $subsourcePath -targetPath $subtargetPath + } else { + $sourceItemPath = $sourcePath + '\' + $item.Name + $targetItemPath = $targetPath + '\' + $item.Name + if (-not (Test-Path $targetItemPath)) { + # only copies non-existing files + if (-not (Test-Path $targetPath)) { + # if folder doesn't exist, creates it + $null = New-Item -ItemType 'directory' -Path $targetPath + } + $null = Copy-Item $sourceItemPath $targetItemPath + } else { + Write-Verbose "[$sourceItemPath] already exists" + } + } + } +} + +function Install-CustomModule { + + <# + .SYNOPSIS + Installes given PowerShell modules + + .DESCRIPTION + Installes given PowerShell modules + + .PARAMETER Module + Required. Modules to be installed, must be Object + @{ + Name = 'Name' + Version = '1.0.0' # Optional + } + + .PARAMETER InstalledModuleList + Optional. Modules that are already installed on the machine. Can be fetched via 'Get-Module -ListAvailable' + + .EXAMPLE + Install-CustomModule @{ Name = 'Pester' } C:\Modules + + Installes pester and saves it to C:\Modules + #> + + [CmdletBinding(SupportsShouldProcess)] + Param ( + [Parameter(Mandatory = $true)] + [Hashtable] $Module, + + [Parameter(Mandatory = $false)] + [object[]] $InstalledModuleList = @() + ) + + # Remove exsisting module in session + if (Get-Module $Module -ErrorAction 'SilentlyContinue') { + try { + Remove-Module $Module -Force + } catch { + LogError('Unable to remove module [{0}] because of exception [{1}]. Stack Trace: [{2}]' -f $Module.Name, $_.Exception, $_.ScriptStackTrace) + } + } + + # Install found module + $moduleImportInputObject = @{ + name = $Module.Name + Repository = 'PSGallery' + } + if ($Module.Version) { + $moduleImportInputObject['RequiredVersion'] = $Module.Version + } + + # Get all modules that match a certain name. In case of e.g. 'Az' it returns several. + $foundModules = Find-Module @moduleImportInputObject + + foreach ($foundModule in $foundModules) { + + # Check if already installed as required + if ($alreadyInstalled = $InstalledModule | Where-Object { $_.Name -eq $Module.Name }) { + if ($Module.Version) { + $alreadyInstalled = $alreadyInstalled | Where-Object { $_.Version -eq $Module.Version } + } else { + # Get latest in case of multiple + $alreadyInstalled = ($alreadyInstalled | Sort-Object -Property Version -Descending)[0] + } + LogInfo('[{0}] Module is already installed with version [{1}]' -f $alreadyInstalled.Name, $alreadyInstalled.Version) -Verbose + continue + } + + # Check if not to be excluded + if ($Module.ExcludeModules -and $Module.excludeModules.contains($foundModule.Name)) { + LogInfo('[{0}] Module is configured to be ignored.' -f $foundModule.Name) -Verbose + continue + } + + if ($PSCmdlet.ShouldProcess('Module [{0}]' -f $foundModule.Name, 'Install')) { + $dependenciesAlreadyAvailable = Get-AreDependenciesAvailable -InstalledModuleList $InstalledModuleList -Module $foundModule + if ($dependenciesAlreadyAvailable) { + LogInfo('[{0}] Install module with version [{1}] exluding dependencies.' -f $foundModule.Name, $foundModule.Version) -Verbose + Install-RawModule -ModuleName $foundModule.Name -ModuleVersion $foundModule.Version + } else { + LogInfo('[{0}] Install module with version [{1}] including dependencies' -f $foundModule.Name, $foundModule.Version) -Verbose + $foundModule | Install-Module -Force -SkipPublisherCheck -AllowClobber + } + } + + if ($installed = (Get-Module -Name $foundModule.Name -ListAvailable | Where-Object { $_.Version -eq $foundModule.Version })) { + + # Adding new module to list of 'already installed' modules + $InstalledModuleList += $installed + + $installPath = Split-Path (Split-Path (Split-Path $installed[0].Path)) + LogInfo('[{0}] Module was installed in path [{2}]' -f $installed[0].Name, $installed[0].Version, $installPath) -Verbose + } else { + LogError('Installation of module [{0}] failed' -f $foundModule.Name) + } + } +} + +function Install-RawModule { + <# + .SYNOPSIS + Install a module without any of its dependencies + + .DESCRIPTION + Modules are downloaded from the PSGallery and stored in the first path of the PSModulePath environment variable + + .PARAMETER ModuleName + Mandatory. The name of the module to install + + .PARAMETER ModuleVersion + Mandatory. The name of the module version to install + + .EXAMPLE + Install-RawModule -ModuleName 'Az.Compute' -ModuleVersion '4.27.0' + + Install module 'Az.Compute' in version '4.27.0' in the default PSModule installation path + #> + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory)] + [string] $ModuleName, + + [Parameter(Mandatory)] + [string] $ModuleVersion + ) + + $url = "https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion" + + $downloadFolder = Join-Path ([System.IO.Path]::GetTempPath()) 'modulesToInstall' + $downloadPath = Join-Path $downloadFolder "$ModuleName.$ModuleVersion.zip" # Assuming [.zip] instead of [.nupkg] + $expandedRootPath = Join-Path $downloadFolder 'formattedModules' + $expandedPath = Join-Path $expandedRootPath (Split-Path $downloadPath -LeafBase) + $newModuleRootFolder = Join-Path $expandedRootPath $ModuleName + $newModuleRawVersionFolder = (Join-Path $newModuleRootFolder (Split-Path $expandedPath -Leaf)) + + if ($IsWindows) { $psModulesPath = ($env:PSModulePath -split ';')[0] } + else { $psModulesPath = ($env:PSModulePath -split ':')[0] } + + $finalVersionPath = Join-Path $psModulesPath $ModuleName $ModuleVersion + + # 1. Download nupkg package + if (-not (Test-Path $downloadFolder)) { + if ($PSCmdlet.ShouldProcess("Folder [$downloadFolder]", 'Create')) { + $null = New-Item $downloadFolder -ItemType 'Directory' + } + } + try { + if (-not (Test-Path $downloadPath)) { + if ($PSCmdlet.ShouldProcess("From url [$url] to path [$downloadPath]", 'Download')) { + (New-Object System.Net.WebClient).DownloadFile($Url, $downloadPath) + } + } + } catch { + LogError("Download FAILED: $_") + } + + if ($IsWindows) { + # Not supported in Linux + if ($PSCmdlet.ShouldProcess("File in path [$downloadFolder]", 'Unblock')) { + Unblock-File -Path $downloadPath + } + } + + # 2. Expand Achive + if (-not (Test-Path $expandedPath)) { + if ($PSCmdlet.ShouldProcess("File [$downloadPath] to path [$expandedPath]", 'Expand/Unzip')) { + $null = Expand-Archive -Path $downloadPath -DestinationPath $expandedPath -PassThru + } + } + + # 3. Remove files & folders - Optional + foreach ($fileOrFolderToRemove in @('PSGetModuleInfo.xml', '[Content_Types].xml', '_rels', 'package')) { + $filePath = Join-Path $expandedPath $fileOrFolderToRemove + if (Test-Path -LiteralPath $filePath) { + if ($PSCmdlet.ShouldProcess("Item [$filePath]", 'Remove')) { + $null = Remove-Item -LiteralPath $filePath -Force -Recurse -ErrorAction 'SilentlyContinue' + } + } + } + + # 4. Rename folder + $modulename, $moduleVersion = [regex]::Match((Split-Path $downloadPath -LeafBase), '([a-zA-Z.]+)\.([0-9.]+)').Captures.Groups.value[1, 2] + # Rename-Item -Path $expandedPath -NewName + if (-not (Test-Path $newModuleRootFolder)) { + if ($PSCmdlet.ShouldProcess("Folder [$newModuleRootFolder]", 'Create')) { + $null = New-Item -Path $newModuleRootFolder -ItemType 'Directory' + } + if ($PSCmdlet.ShouldProcess("All items from [$expandedPath] to path [$newModuleRootFolder]", 'Move')) { + $null = Move-Item -LiteralPath $expandedPath -Destination $newModuleRootFolder -Force + } + if ($PSCmdlet.ShouldProcess("Folder [$newModuleRawVersionFolder] to name [$ModuleVersion]", 'Rename')) { + $null = Rename-Item -Path (Join-Path $newModuleRootFolder (Split-Path $expandedPath -Leaf)) -NewName $ModuleVersion + } + } + + # 5. Move folder + if (-not (Test-Path $finalVersionPath)) { + if ($PSCmdlet.ShouldProcess("All items from [$newModuleRootFolder] to path [$psModulesPath]", 'Move')) { + $null = Move-Item -LiteralPath $newModuleRootFolder -Destination $psModulesPath -Force + } + } +} + +function Get-AreDependenciesAvailable { + <# + .SYNOPSIS + Check if all depenencies for a given module are already available in the required minimum version. + + .DESCRIPTION + Check if all depenencies for a given module are already available in the required minimum version. + Returns '$true' if they are, otherwise '$false' + + .PARAMETER InstalledModuleList + Optional. A list of already installed modules. + + .PARAMETER Module + Optional. The module to check the dependencies for + + .EXAMPLE + Get-AreDependenciesAvailable -InstalledModuleList (Get-Module -ListAvailable) -Module (Find-Module 'Az.Compute') + + Check if all dependencies of 'Az.Compute' are part of the already installed modules. + #> + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [object[]] $InstalledModuleList = @(), + + [Parameter(Mandatory = $false)] + [PSCustomObject] $Module + ) + + foreach ($depenency in $Module.dependencies) { + + $dependencyModuleName = $depenency.Name + $dependencyModuleMinimumVersion = [version] ($depenency.minimumVersion) + + $matchingModulesByName = $InstalledModuleList | Where-Object { $_.Name -eq $dependencyModuleName } + $matchingModules = $matchingModulesByName | Where-Object { ([version] $_.Version) -ge $dependencyModuleMinimumVersion } + + if ($matchingModules.Count -eq 0) { + return $false + } + } + + return $true +} +#endregion + + +$StartTime = Get-Date +$progressPreference = 'SilentlyContinue' +LogInfo('#############################################') +LogInfo('# Entering Initialize-LinuxSoftware.ps1 #') +LogInfo('#############################################') + +########################### +## Install Azure CLI ## +########################### +LogInfo('Install azure cli start') +curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash +LogInfo('Install azure cli end') + +############################### +## Install Extensions CLI # +############################### + +LogInfo('Install cli exentions start') +$Extensions = @( + 'azure-devops' +) +foreach ($extension in $Extensions) { + if ((az extension list-available -o json | ConvertFrom-Json).Name -notcontains $extension) { + Write-Verbose "Adding CLI extension '$extension'" + az extension add --name $extension + } +} +LogInfo('Install cli exentions end') + +########################## +## Install Az Bicep # +########################## +LogInfo('Install az bicep exention start') +az bicep install +LogInfo('Install az bicep exention end') + +######################### +## Install Kubectl # +######################### +LogInfo('Install kubectl start') +sudo az aks install-cli +LogInfo('Install kubectl end') + +######################## +## Install Docker # +######################## +LogInfo('Install docker start') +sudo apt-get update + +sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common +curl -fsSL 'https://download.docker.com/linux/ubuntu/gpg' | sudo apt-key add - + +LogInfo('Install docker - Add repository') +sudo add-apt-repository 'deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable' -y + +LogInfo('Install docker - adp update') +sudo apt-get update + +LogInfo('Install docker - adp-cache docker-ce policy') +apt-cache policy 'docker-ce' + +LogInfo('Install docker - adp update') +sudo apt-get update + +LogInfo('Install docker - adp-get install docker-ce') +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y 'docker-ce' + +LogInfo('Install docker - chmod') +sudo chmod 666 '/var/run/docker.sock' # All users can read and write but cannot execute the file/folder +LogInfo('Install docker end') + +########################### +## Install Terraform ## +########################### +LogInfo('Install Terraform start') +$terraformReleasesUrl = 'https://api.github.com/repos/hashicorp/terraform/releases/latest' +$latestTerraformVersion = (Invoke-WebRequest -Uri $terraformReleasesUrl -UseBasicParsing | ConvertFrom-Json).name.Replace('v', '') +LogInfo("Fetched latest available version: [$latestTerraformVersion]") + +LogInfo("Using version: [$latestTerraformVersion]") +sudo DEBIAN_FRONTEND=noninteractive apt-get install unzip +wget ('https://releases.hashicorp.com/terraform/{0}/terraform_{0}_linux_amd64.zip' -f $latestTerraformVersion) +unzip ('terraform_{0}_linux_amd64.zip' -f $latestTerraformVersion ) +sudo mv terraform /usr/local/bin/ +terraform --version +LogInfo('Install Terraform end') + +####################### +## Install AzCopy # +####################### +# Cleanup +sudo rm ./downloadazcopy-v10-linux* +sudo rm ./azcopy_linux_amd64_* +sudo rm /usr/bin/azcopy + +# Download +wget https://aka.ms/downloadazcopy-v10-linux -O 'downloadazcopy-v10-linux.tar.gz' + +# Expand (to azcopy_linux_amd64_x.x.x) +tar -xzvf downloadazcopy-v10-linux.tar.gz + +# Move +sudo cp ./azcopy_linux_amd64_*/azcopy /usr/bin/ + +################################## +## Install .NET (for Nuget) ## +################################## +# Source: https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#1804- +LogInfo('Install dotnet (for nuget) start') + +# .NET-Core SDK +sudo apt-get update +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y dotnet-sdk-8.0 + +# .NET-Core Runtime +sudo apt-get update +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y aspnetcore-runtime-8.0 + +LogInfo('Install dotnet (for nuget) end') + +########################### +## Install BICEP CLI ## +########################### +LogInfo('Install BICEP start') + +# Fetch the latest Bicep CLI binary +curl -Lo bicep 'https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64' +# Mark it as executable +chmod +x ./bicep +# Add bicep to your PATH (requires admin) +sudo mv ./bicep /usr/local/bin/bicep +LogInfo('Install BICEP end') + +############################### +## Install PowerShellGet ## +############################### +LogInfo('Install latest PowerShellGet start') +$null = Install-Module 'PowerShellGet' -Force +LogInfo('Install latest PowerShellGet end') + +LogInfo('Import PowerShellGet start') +$null = Import-PackageProvider PowerShellGet -Force +LogInfo('Import PowerShellGet end') + +#################################### +## Install PowerShell Modules ## +#################################### +$Modules = @( + @{ Name = 'Pester'; Version = '5.1.1' }, + @{ Name = 'PSScriptAnalyzer' }, + @{ Name = 'powershell-yaml' }, + @{ Name = 'Azure.*'; ExcludeModules = @('Azure.Storage') }, # Azure.Storage has AzureRM dependency + @{ Name = 'Logging' }, + @{ Name = 'PoshRSJob' }, + @{ Name = 'ThreadJob' }, + @{ Name = 'JWTDetails' }, + @{ Name = 'OMSIngestionAPI' }, + @{ Name = 'Az.*' }, + @{ Name = 'AzureAD' }, + @{ Name = 'ImportExcel' } +) +$count = 0 +LogInfo('Try installing:') +$modules | ForEach-Object { + LogInfo('- [{0}]. [{1}]' -f $count, $_.Name) + $count++ +} + +# Load already installed modules +$installedModules = Get-Module -ListAvailable + +LogInfo('Install-CustomModule start') +$count = 0 +Foreach ($Module in $Modules) { + LogInfo('=====================') + LogInfo('HANDLING MODULE [{0}] [{1}/{2}]' -f $Module.Name, $count, $Modules.Count) + LogInfo('=====================') + # Installing New Modules and Removing Old + $null = Install-CustomModule -Module $Module -InstalledModuleList $installedModules + $count++ +} +LogInfo('Install-CustomModule end') + + +######################################### +## Post Installation Configuration ## +######################################### +LogInfo('Copy PS modules to expected location start') +$targetPath = '/opt/microsoft/powershell/7/Modules' +$sourcePaths = @('/home/packer/.local/share/powershell/Modules', '/root/.local/share/powershell/Modules') +foreach ($sourcePath in $sourcePaths) { + if (Test-Path $sourcePath) { + LogInfo("Copying from [$sourcePath] to [$targetPath]") + $null = Copy-FileAndFolderList -sourcePath $sourcePath -targetPath $targetPath + } +} +LogInfo('Copy PS modules end') + +$elapsedTime = (Get-Date) - $StartTime +$totalTime = '{0:HH:mm:ss}' -f ([datetime]$elapsedTime.Ticks) +LogInfo("Execution took [$totalTime]") +LogInfo('############################################') +LogInfo('# Exiting Initialize-LinuxSoftware.ps1 #') +LogInfo('############################################') + +return 0 +#endregion diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Initialize-WindowsSoftware.ps1 b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Initialize-WindowsSoftware.ps1 new file mode 100644 index 0000000000..4672d2b3b6 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Initialize-WindowsSoftware.ps1 @@ -0,0 +1,792 @@ +#requires -Version 6.0 + +#region Functions +function LogInfo($message) { + Log 'Info' $message +} + +function LogError($message) { + Log 'Error' $message +} + +function LogWarning($message) { + Log 'Warning' $message +} + +function Log { + + <# + .SYNOPSIS + Creates a log file and stores logs based on categories with tab seperation + + .PARAMETER category + Category to put into the trace + + .PARAMETER message + Message to be loged + + .EXAMPLE + Log 'Info' 'Message' + + #> + + Param ( + [Parameter(Mandatory = $false)] + [string] $category = 'Info', + + [Parameter(Mandatory = $true)] + [string] $message + ) + + $date = Get-Date + $content = "[$date]`t$category`t`t$message`n" + Write-Verbose $Content -Verbose + + $FilePath = Join-Path ([System.IO.Path]::GetTempPath()) 'log.log' + if (-not (Test-Path $FilePath)) { + Write-Verbose "Log file not found, create new in path: [$FilePath]" -Verbose + $null = New-Item -ItemType 'File' -Path $FilePath -Force + } + Add-Content -Path $FilePath -Value $content -ErrorAction 'Stop' +} + +function Install-CustomModule { + + <# + .SYNOPSIS + Installes given PowerShell modules + + .DESCRIPTION + Installes given PowerShell modules + + .PARAMETER Module + Required. Modules to be installed, must be Object + @{ + Name = 'Name' + Version = '1.0.0' # Optional + } + + .PARAMETER InstalledModuleList + Optional. Modules that are already installed on the machine. Can be fetched via 'Get-Module -ListAvailable' + + .EXAMPLE + Install-CustomModule @{ Name = 'Pester' } C:\Modules + + Installes pester and saves it to C:\Modules + #> + + [CmdletBinding(SupportsShouldProcess)] + Param ( + [Parameter(Mandatory = $true)] + [Hashtable] $Module, + + [Parameter(Mandatory = $false)] + [object[]] $InstalledModuleList = @() + ) + + # Remove exsisting module in session + if (Get-Module $Module -ErrorAction 'SilentlyContinue') { + try { + Remove-Module $Module -Force + } catch { + LogError('Unable to remove module [{0}] because of exception [{1}]. Stack Trace: [{2}]' -f $Module.Name, $_.Exception, $_.ScriptStackTrace) + } + } + + # Install found module + $moduleImportInputObject = @{ + name = $Module.Name + Repository = 'PSGallery' + } + if ($Module.Version) { + $moduleImportInputObject['RequiredVersion'] = $Module.Version + } + + # Get all modules that match a certain name. In case of e.g. 'Az' it returns several. + $foundModules = Find-Module @moduleImportInputObject + + foreach ($foundModule in $foundModules) { + + # Check if already installed as required + if ($alreadyInstalled = $InstalledModule | Where-Object { $_.Name -eq $Module.Name }) { + if ($Module.Version) { + $alreadyInstalled = $alreadyInstalled | Where-Object { $_.Version -eq $Module.Version } + } else { + # Get latest in case of multiple + $alreadyInstalled = ($alreadyInstalled | Sort-Object -Property Version -Descending)[0] + } + LogInfo('[{0}] Module is already installed with version [{1}]' -f $alreadyInstalled.Name, $alreadyInstalled.Version) -Verbose + continue + } + + # Check if not to be excluded + if ($Module.ExcludeModules -and $Module.excludeModules.contains($foundModule.Name)) { + LogInfo('[{0}] Module is configured to be ignored.' -f $foundModule.Name) -Verbose + continue + } + + if ($PSCmdlet.ShouldProcess('Module [{0}]' -f $foundModule.Name, 'Install')) { + $dependenciesAlreadyAvailable = Get-AreDependenciesAvailable -InstalledModuleList $InstalledModuleList -Module $foundModule + if ($dependenciesAlreadyAvailable) { + LogInfo('[{0}] Install module with version [{1}] exluding dependencies.' -f $foundModule.Name, $foundModule.Version) -Verbose + Install-RawModule -ModuleName $foundModule.Name -ModuleVersion $foundModule.Version + } else { + LogInfo('[{0}] Install module with version [{1}] including dependencies' -f $foundModule.Name, $foundModule.Version) -Verbose + $foundModule | Install-Module -Force -SkipPublisherCheck -AllowClobber + } + } + + if ($installed = (Get-Module -Name $foundModule.Name -ListAvailable | Where-Object { $_.Version -eq $foundModule.Version })) { + + # Adding new module to list of 'already installed' modules + $InstalledModuleList += $installed + + $installPath = Split-Path (Split-Path (Split-Path $installed[0].Path)) + LogInfo('[{0}] Module was installed in path [{2}]' -f $installed[0].Name, $installed[0].Version, $installPath) -Verbose + } else { + LogError('Installation of module [{0}] failed' -f $foundModule.Name) + } + } +} + +function Install-RawModule { + <# + .SYNOPSIS + Install a module without any of its dependencies + + .DESCRIPTION + Modules are downloaded from the PSGallery and stored in the first path of the PSModulePath environment variable + + .PARAMETER ModuleName + Mandatory. The name of the module to install + + .PARAMETER ModuleVersion + Mandatory. The name of the module version to install + + .EXAMPLE + Install-RawModule -ModuleName 'Az.Compute' -ModuleVersion '4.27.0' + + Install module 'Az.Compute' in version '4.27.0' in the default PSModule installation path + #> + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory)] + [string] $ModuleName, + + [Parameter(Mandatory)] + [string] $ModuleVersion + ) + + $url = "https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion" + + $downloadFolder = Join-Path ([System.IO.Path]::GetTempPath()) 'modulesToInstall' + $downloadPath = Join-Path $downloadFolder "$ModuleName.$ModuleVersion.zip" # Assuming [.zip] instead of [.nupkg] + $expandedRootPath = Join-Path $downloadFolder 'formattedModules' + $expandedPath = Join-Path $expandedRootPath (Split-Path $downloadPath -LeafBase) + $newModuleRootFolder = Join-Path $expandedRootPath $ModuleName + $newModuleRawVersionFolder = (Join-Path $newModuleRootFolder (Split-Path $expandedPath -Leaf)) + + if ($IsWindows) { $psModulesPath = ($env:PSModulePath -split ';')[0] } + else { $psModulesPath = ($env:PSModulePath -split ':')[0] } + + $finalVersionPath = Join-Path $psModulesPath $ModuleName $ModuleVersion + + # 1. Download nupkg package + if (-not (Test-Path $downloadFolder)) { + if ($PSCmdlet.ShouldProcess("Folder [$downloadFolder]", 'Create')) { + $null = New-Item $downloadFolder -ItemType 'Directory' + } + } + try { + if (-not (Test-Path $downloadPath)) { + if ($PSCmdlet.ShouldProcess("From url [$url] to path [$downloadPath]", 'Download')) { + (New-Object System.Net.WebClient).DownloadFile($Url, $downloadPath) + } + } + } catch { + LogError("Download FAILED: $_") + } + + if ($IsWindows) { + # Not supported in Linux + if ($PSCmdlet.ShouldProcess("File in path [$downloadFolder]", 'Unblock')) { + $null = Unblock-File -Path $downloadPath + } + } + + + # 2. Expand Achive + if (-not (Test-Path $expandedPath)) { + if ($PSCmdlet.ShouldProcess("File [$downloadPath] to path [$expandedPath]", 'Expand/Unzip')) { + $null = Expand-Archive -Path $downloadPath -DestinationPath $expandedPath -PassThru + } + } + + # 3. Remove files & folders - Optional + foreach ($fileOrFolderToRemove in @('PSGetModuleInfo.xml', '[Content_Types].xml', '_rels', 'package')) { + $filePath = Join-Path $expandedPath $fileOrFolderToRemove + if (Test-Path -LiteralPath $filePath) { + if ($PSCmdlet.ShouldProcess("Item [$filePath]", 'Remove')) { + $null = Remove-Item -LiteralPath $filePath -Force -Recurse -ErrorAction 'SilentlyContinue' + } + } + } + + # 4. Rename folder + $modulename, $moduleVersion = [regex]::Match((Split-Path $downloadPath -LeafBase), '([a-zA-Z.]+)\.([0-9.]+)').Captures.Groups.value[1, 2] + # Rename-Item -Path $expandedPath -NewName + if (-not (Test-Path $newModuleRootFolder)) { + if ($PSCmdlet.ShouldProcess("Folder [$newModuleRootFolder]", 'Create')) { + $null = New-Item -Path $newModuleRootFolder -ItemType 'Directory' + } + if ($PSCmdlet.ShouldProcess("All items from [$expandedPath] to path [$newModuleRootFolder]", 'Move')) { + $null = Move-Item -LiteralPath $expandedPath -Destination $newModuleRootFolder -Force + } + if ($PSCmdlet.ShouldProcess("Folder [$newModuleRawVersionFolder] to name [$ModuleVersion]", 'Rename')) { + $null = Rename-Item -Path (Join-Path $newModuleRootFolder (Split-Path $expandedPath -Leaf)) -NewName $ModuleVersion + } + } + + # 5. Move folder + if (-not (Test-Path $finalVersionPath)) { + if ($PSCmdlet.ShouldProcess("All items from [$newModuleRootFolder] to path [$psModulesPath]", 'Move')) { + $null = Move-Item -LiteralPath $newModuleRootFolder -Destination $psModulesPath -Force + } + } +} + +function Get-AreDependenciesAvailable { + <# + .SYNOPSIS + Check if all depenencies for a given module are already available in the required minimum version. + + .DESCRIPTION + Check if all depenencies for a given module are already available in the required minimum version. + Returns '$true' if they are, otherwise '$false' + + .PARAMETER InstalledModuleList + Optional. A list of already installed modules. + + .PARAMETER Module + Optional. The module to check the dependencies for + + .EXAMPLE + Get-AreDependenciesAvailable -InstalledModuleList (Get-Module -ListAvailable) -Module (Find-Module 'Az.Compute') + + Check if all dependencies of 'Az.Compute' are part of the already installed modules. + #> + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [object[]] $InstalledModuleList = @(), + + [Parameter(Mandatory = $false)] + [PSCustomObject] $Module + ) + + foreach ($depenency in $Module.dependencies) { + + $dependencyModuleName = $depenency.Name + $dependencyModuleMinimumVersion = [version] ($depenency.minimumVersion) + + $matchingModulesByName = $InstalledModuleList | Where-Object { $_.Name -eq $dependencyModuleName } + $matchingModules = $matchingModulesByName | Where-Object { ([version] $_.Version) -ge $dependencyModuleMinimumVersion } + + if ($matchingModules.Count -eq 0) { + return $false + } + } + + return $true +} + +function Set-PowerShellOutputRedirectionBugFix { + + [CmdletBinding(SupportsShouldProcess)] + param () + + $poshMajorVerion = $PSVersionTable.PSVersion.Major + + if ($poshMajorVerion -lt 4) { + try { + # http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ plus comments + $bindingFlags = [Reflection.BindingFlags] 'Instance,NonPublic,GetField' + $objectRef = $host.GetType().GetField('externalHostRef', $bindingFlags).GetValue($host) + $bindingFlags = [Reflection.BindingFlags] 'Instance,NonPublic,GetProperty' + $consoleHost = $objectRef.GetType().GetProperty('Value', $bindingFlags).GetValue($objectRef, @()) + [void] $consoleHost.GetType().GetProperty('IsStandardOutputRedirected', $bindingFlags).GetValue($consoleHost, @()) + $bindingFlags = [Reflection.BindingFlags] 'Instance,NonPublic,GetField' + $field = $consoleHost.GetType().GetField('standardOutputWriter', $bindingFlags) + + if ($PSCmdlet.ShouldProcess('OutputWriter field [Out]', 'Set')) { + $field.SetValue($consoleHost, [Console]::Out) + } + + [void] $consoleHost.GetType().GetProperty('IsStandardErrorRedirected', $bindingFlags).GetValue($consoleHost, @()) + $field2 = $consoleHost.GetType().GetField('standardErrorWriter', $bindingFlags) + + if ($PSCmdlet.ShouldProcess('OutputWriter field [Error]', 'Set')) { + $field2.SetValue($consoleHost, [Console]::Error) + } + } catch { + LogInfo( 'Unable to apply redirection fix.') + } + } +} + +function Get-Downloader { + param ( + [string]$url + ) + + $downloader = New-Object System.Net.WebClient + + $defaultCreds = [System.Net.CredentialCache]::DefaultCredentials + if ($null -ne $defaultCreds) { + $downloader.Credentials = $defaultCreds + } + + if ($env:chocolateyIgnoreProxy -eq 'true') { + Write-Debug 'Explicitly bypassing proxy due to user environment variable' + $downloader.Proxy = [System.Net.GlobalProxySelection]::GetEmptyWebProxy() + } else { + # check if a proxy is required + $explicitProxy = $env:chocolateyProxyLocation + $explicitProxyUser = $env:chocolateyProxyUser + $explicitProxyPassword = $env:chocolateyProxyPassword + if ($null -ne $explicitProxy -and $explicitProxy -ne '') { + # explicit proxy + $proxy = New-Object System.Net.WebProxy($explicitProxy, $true) + if ($null -ne $explicitProxyPassword -and $explicitProxyPassword -ne '') { + $passwd = ConvertTo-SecureString $explicitProxyPassword -AsPlainText -Force + $proxy.Credentials = New-Object System.Management.Automation.PSCredential ($explicitProxyUser, $passwd) + } + + Write-Debug "Using explicit proxy server '$explicitProxy'." + $downloader.Proxy = $proxy + + } elseif (-not $downloader.Proxy.IsBypassed($url)) { + # system proxy (pass through) + $creds = $defaultCreds + if ($null -eq $creds) { + Write-Debug 'Default credentials were null. Attempting backup method' + $cred = Get-Credential + $creds = $cred.GetNetworkCredential() + } + + $proxyaddress = $downloader.Proxy.GetProxy($url).Authority + Write-Debug "Using system proxy server '$proxyaddress'." + $proxy = New-Object System.Net.WebProxy($proxyaddress) + $proxy.Credentials = $creds + $downloader.Proxy = $proxy + } + } + + return $downloader +} + +function Get-DownloadString { + param ( + [string]$url + ) + $downloader = Get-Downloader $url + + return $downloader.DownloadString($url) +} + +function Get-DownloadedFile { + param ( + [string]$url, + [string]$file + ) + LogInfo( "Downloading $url to $file") + $downloader = Get-Downloader $url + + $downloader.DownloadFile($url, $file) +} + +function Set-SecurityProtocol { + + [CmdletBinding(SupportsShouldProcess)] + param ( + ) + + # Attempt to set highest encryption available for SecurityProtocol. + # PowerShell will not set this by default (until maybe .NET 4.6.x). This + # will typically produce a message for PowerShell v2 (just an info + # message though) + try { + # Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48) + # Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't + # exist in .NET 4.0, even though they are addressable if .NET 4.5+ is + # installed (.NET 4.5 is an in-place upgrade). + if ($PSCmdlet.ShouldProcess('Security protocol', 'Set')) { + [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48 + } + } catch { + LogInfo( 'Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to do one or more of the following: (1) upgrade to .NET Framework 4.5+ and PowerShell v3, (2) specify internal Chocolatey package location (set $env:chocolateyDownloadUrl prior to install or host the package internally), (3) use the Download + PowerShell method of install. See https://chocolatey.org/install for all install options.') + } +} + +function Install-Choco { + + LogInfo( 'Install choco') + + LogInfo( 'Invoke install.ps1 content') + $chocTempDir = Join-Path ([System.IO.Path]::GetTempPath()) 'chocolatey' + $tempDir = Join-Path $chocTempDir 'chocInstall' + if (-not [System.IO.Directory]::Exists($tempDir)) { [void][System.IO.Directory]::CreateDirectory($tempDir) } + $file = Join-Path $tempDir 'chocolatey.zip' + + Set-PowerShellOutputRedirectionBugFix + + Set-SecurityProtocol + + LogInfo( 'Getting latest version of the Chocolatey package for download.') + $url = 'https://chocolatey.org/api/v2/Packages()?$filter=((Id%20eq%20%27chocolatey%27)%20and%20(not%20IsPrerelease))%20and%20IsLatestVersion' + [xml]$result = Get-DownloadString $url + $url = $result.feed.entry.content.src + + # Download the Chocolatey package + LogInfo("Getting Chocolatey from $url.") + Get-DownloadedFile $url $file + + # Determine unzipping method + # 7zip is the most compatible so use it by default + $7zaExe = Join-Path $tempDir '7za.exe' + $unzipMethod = '7zip' + if ($env:chocolateyUseWindowsCompression -eq 'true') { + LogInfo( 'Using built-in compression to unzip') + $unzipMethod = 'builtin' + } elseif (-Not (Test-Path ($7zaExe))) { + LogInfo( 'Downloading 7-Zip commandline tool prior to extraction.') + # download 7zip + Get-DownloadedFile 'https://chocolatey.org/7za.exe' "$7zaExe" + } + + # unzip the package + LogInfo("Extracting $file to $tempDir...") + if ($unzipMethod -eq '7zip') { + LogInfo('Unzip with 7zip') + $params = "x -o`"$tempDir`" -bd -y `"$file`"" + # use more robust Process as compared to Start-Process -Wait (which doesn't + # wait for the process to finish in PowerShell v3) + $process = New-Object System.Diagnostics.Process + $process.StartInfo = New-Object System.Diagnostics.ProcessStartInfo($7zaExe, $params) + $process.StartInfo.RedirectStandardOutput = $true + $process.StartInfo.UseShellExecute = $false + $process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden + $process.Start() | Out-Null + $process.BeginOutputReadLine() + $process.WaitForExit() + $exitCode = $process.ExitCode + $process.Dispose() + $errorMessage = "Unable to unzip package using 7zip. Perhaps try setting `$env:chocolateyUseWindowsCompression = 'true' and call install again. Error:" + switch ($exitCode) { + 0 { LogInfo('Processed zip'); break } + 1 { throw "$errorMessage Some files could not be extracted" } + 2 { throw "$errorMessage 7-Zip encountered a fatal error while extracting the files" } + 7 { throw "$errorMessage 7-Zip command line error" } + 8 { throw "$errorMessage 7-Zip out of memory" } + 255 { throw "$errorMessage Extraction cancelled by the user" } + default { throw "$errorMessage 7-Zip signalled an unknown error (code $exitCode)" } + } + } else { + LogInfo('Unzip without 7zip') + if ($PSVersionTable.PSVersion.Major -lt 5) { + try { + $shellApplication = New-Object -com shell.application + $zipPackage = $shellApplication.NameSpace($file) + $destinationFolder = $shellApplication.NameSpace($tempDir) + $destinationFolder.CopyHere($zipPackage.Items(), 0x10) + } catch { + throw "Unable to unzip package using built-in compression. Set `$env:chocolateyUseWindowsCompression = 'false' and call install again to use 7zip to unzip. Error: `n $_" + } + } else { + $null = Expand-Archive -Path $file -DestinationPath $tempDir -Force -PassThru + } + } + + # Call chocolatey install + LogInfo( 'Installing chocolatey on this machine') + $toolsFolder = Join-Path $tempDir 'tools' + $chocInstallPS1 = Join-Path $toolsFolder 'chocolateyInstall.ps1' + + & $chocInstallPS1 + + LogInfo( 'Ensuring chocolatey commands are on the path') + $chocInstallVariableName = 'ChocolateyInstall' + $chocoPath = [Environment]::GetEnvironmentVariable($chocInstallVariableName) + if ($null -eq $chocoPath -or $chocoPath -eq '') { + $chocoPath = "$env:ALLUSERSPROFILE\Chocolatey" + } + + if (-not (Test-Path ($chocoPath))) { + $chocoPath = "$env:SYSTEMDRIVE\ProgramData\Chocolatey" + } + + $chocoExePath = Join-Path $chocoPath 'bin' + + if ($($env:Path).ToLower().Contains($($chocoExePath).ToLower()) -eq $false) { + $env:Path = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine) + } + + LogInfo( 'Ensuring chocolatey.nupkg is in the lib folder') + $chocoPkgDir = Join-Path $chocoPath 'lib\chocolatey' + $nupkg = Join-Path $chocoPkgDir 'chocolatey.nupkg' + if (-not [System.IO.Directory]::Exists($chocoPkgDir)) { [System.IO.Directory]::CreateDirectory($chocoPkgDir); } + Copy-Item "$file" "$nupkg" -Force -ErrorAction SilentlyContinue +} + + +function Uninstall-AzureRM { + <# + .SYNOPSIS + Removes AzureRM from system + + .EXAMPLE + Uninstall-AzureRM + Removes AzureRM from system + + #> + + LogInfo('Remove Modules from context start') + Get-Module 'AzureRM.*' | Remove-Module + LogInfo('Remaining AzureRM modules: {0}' -f ((Get-Module 'AzureRM.*').Name -join ' | ')) + LogInfo('Remove Modules from context end') + + # Uninstall AzureRm Modules + try { + Get-Module 'AzureRm.*' -ListAvailable | Uninstall-Module -Force + } catch { + LogError("Unable to remove AzureRM Module: $($_.Exception) found, $($_.ScriptStackTrace)") + } + + try { + $AzureRMModuleFolder = 'C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager' + if (Test-Path $AzureRMModuleFolder) { + $null = Remove-Item $AzureRMModuleFolder -Force -Recurse + LogInfo("Removed $AzureRMModuleFolder") + } + } catch { + LogError("Unable to remove $AzureRMModuleFolder") + } + + LogInfo('Remaining installed AzureRMModule: {0}' -f ((Get-Module 'AzureRM.*' -ListAvailable).Name -join ' | ')) +} + +function Copy-FileAndFolderList { + + param( + [string] $sourcePath, + [string] $targetPath + ) + + $itemsFrom = Get-ChildItem $sourcePath + foreach ($item in $itemsFrom) { + if ($item.PSIsContainer) { + $subsourcePath = $sourcePath + '\' + $item.BaseName + $subtargetPath = $targetPath + '\' + $item.BaseName + $null = Copy-FileAndFolderList -sourcePath $subsourcePath -targetPath $subtargetPath + } else { + $sourceItemPath = $sourcePath + '\' + $item.Name + $targetItemPath = $targetPath + '\' + $item.Name + if (-not (Test-Path $targetItemPath)) { + # only copies non-existing files + if (-not (Test-Path $targetPath)) { + # if folder doesn't exist, creates it + $null = New-Item -ItemType 'directory' -Path $targetPath + } + $null = Copy-Item $sourceItemPath $targetItemPath + } else { + Write-Verbose "[$sourceItemPath] already exists" + } + } + } +} +#endregion + +$StartTime = Get-Date +$progressPreference = 'SilentlyContinue' +LogInfo('###############################################') +LogInfo('# Entering Initialize-WindowsSoftware.ps1 #') +LogInfo('###############################################') + +LogInfo( 'Set Execution Policy') +Set-ExecutionPolicy Bypass -Scope Process -Force + +####################### +## Install Choco # +####################### +LogInfo('Install-Choco start') +$null = Install-Choco +LogInfo('Install-Choco end') + +########################## +## Install Azure CLI # +########################## +LogInfo('Install azure cli start') +$null = choco install azure-cli -y -v +LogInfo('Install azure cli end') + +############################### +## Install Extensions CLI # +############################### + +LogInfo('Install cli exentions start') +$Extensions = @( + 'azure-devops' +) +foreach ($extension in $Extensions) { + if ((az extension list-available -o json | ConvertFrom-Json).Name -notcontains $extension) { + Write-Verbose "Adding CLI extension '$extension'" + az extension add --name $extension + } +} +LogInfo('Install cli exentions end') + +########################## +## Install Az Bicep # +########################## +LogInfo('Install az bicep exention start') +az bicep install +LogInfo('Install az bicep exention end') + +######################## +## Install docker # +######################## +LogInfo('Install docker start') +choco install docker +LogInfo('Install docker end') + +######################### +## Install Kubectl # +######################### +LogInfo('Install kubectl start') +$null = choco install kubernetes-cli -y -v +LogInfo('Install kubectl end') + +######################## +## Install Docker # +######################## +LogInfo('Install docker start') +$null = choco install docker -y -v +# $null = choco install docker-desktop +LogInfo('Install docker end') + +################################# +## Install PowerShell Core # +################################# +LogInfo('Install powershell core start') +$null = choco install powershell-core -y -v +LogInfo('Install powershell core end') + +########################### +## Install Terraform ## +########################### +LogInfo('Install Terraform start') +$null = choco install terraform -y -v +LogInfo('Install Terraform end') + +####################### +## Install Nuget ## +####################### +LogInfo('Update Package Provider Nuget start') +$null = Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force +LogInfo('Update Package Provider Nuget end') + +####################### +## Install AzCopy # +####################### +LogInfo('Install az copy start') +Invoke-WebRequest -Uri 'https://aka.ms/downloadazcopy-v10-windows' -OutFile 'AzCopy.zip' -UseBasicParsing +$null = Expand-Archive './AzCopy.zip' './AzCopy' -Force -PassThru +Get-ChildItem './AzCopy/*/azcopy.exe' | Move-Item -Destination 'C:\Users\user\AzCopy\AzCopy.exe' +$userenv = [System.Environment]::GetEnvironmentVariable('Path', 'User') +[System.Environment]::SetEnvironmentVariable('PATH', $userenv + ';C:\Users\user\AzCopy', 'User') +LogInfo('Install az copy end') + +############################### +## Install PowerShellGet ## +############################### +LogInfo('Install latest PowerShellGet start') +$null = Install-Module 'PowerShellGet' -Force +LogInfo('Install latest PowerShellGet end') + +LogInfo('Import PowerShellGet start') +$null = Import-PackageProvider PowerShellGet -Force +LogInfo('Import PowerShellGet end') + +#################################### +## Install PowerShell Modules ## +#################################### +$Modules = @( + @{ Name = 'Pester' }, + @{ Name = 'PSScriptAnalyzer' }, + @{ Name = 'powershell-yaml' }, + @{ Name = 'Azure.*'; ExcludeModules = @('Azure.Storage') }, # Azure.Storage has AzureRM dependency + @{ Name = 'Logging' }, + @{ Name = 'PoshRSJob' }, + @{ Name = 'ThreadJob' }, + @{ Name = 'JWTDetails' }, + @{ Name = 'OMSIngestionAPI' }, + @{ Name = 'Az.*' }, + @{ Name = 'AzureAD' }, + @{ Name = 'ImportExcel' } +) +$count = 0 +LogInfo('Try installing:') +$modules | ForEach-Object { + LogInfo('- [{0}]. [{1}]' -f $count, $_.Name) + $count++ +} + +# Load already installed modules +$installedModules = Get-Module -ListAvailable + +LogInfo('Install-CustomModule start') +$count = 0 +Foreach ($Module in $Modules) { + LogInfo('=====================') + LogInfo('HANDLING MODULE [{0}] [{1}/{2}]' -f $Module.Name, $count, $Modules.Count) + LogInfo('=====================') + # Installing New Modules and Removing Old + $null = Install-CustomModule -Module $Module -InstalledModuleList $installedModules + $count++ +} +LogInfo('Install-CustomModule end') + +######################################### +## Post Installation Configuration ## +######################################### +LogInfo('Copy PS modules to expected location start') +$targetPath = 'C:\program files\powershell\7\Modules' +$sourcePaths = @('C:\Users\packer\Documents\PowerShell\Modules') +foreach ($sourcePath in $sourcePaths) { + if (Test-Path $sourcePath) { + LogInfo("Copying from [$sourcePath] to [$targetPath]") + $null = Copy-FileAndFolderList -sourcePath $sourcePath -targetPath $targetPath + } +} +LogInfo('Copy PS modules end') + +######################################### +## Post Installation Configuration ## +######################################### +if (Get-Module AzureRm* -ListAvailable) { + LogInfo('Un-install ARM start') + Uninstall-AzureRm + LogInfo('Un-install ARM end') +} + +$elapsedTime = (Get-Date) - $StartTime +$totalTime = '{0:HH:mm:ss}' -f ([datetime]$elapsedTime.Ticks) +LogInfo("Execution took [$totalTime]") +LogInfo('##############################################') +LogInfo('# Exiting Initialize-WindowsSoftware.ps1 #') +LogInfo('##############################################') + +return 0 +#endregion diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Install-LinuxPowerShell.sh b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Install-LinuxPowerShell.sh new file mode 100644 index 0000000000..e62a245487 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Install-LinuxPowerShell.sh @@ -0,0 +1,44 @@ +# Source: https://learn.microsoft.com/en-us/powershell/scripting/install/install-ubuntu?view=powershell-7.4 + +echo '###########################################' +echo '# Entering Install-LinuxPowerShell.sh #' +echo '###########################################' + +echo '1. Update the list of packages' +sudo apt-get update + +echo '2. Install pre-requisite packages' +sudo apt-get install -y wget apt-transport-https software-properties-common + +echo '3. Get the version of Ubuntu' +# source /etc/os-release +# echo "Found version $VERSION_ID" - empty +VERSION_ID='22.04' + +echo '4. Determine URL' +url=https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-microsoft-prod.deb +echo " Found URL [$url]" + +echo '5. Download the Microsoft repository GPG keys' +wget -q $url + +echo '6. Register the Microsoft repository GPG keys' +sudo dpkg -i packages-microsoft-prod.deb + +echo '7. Delete the Microsoft repository keys file' +rm packages-microsoft-prod.deb + +echo '8. Update the list of products' +sudo apt-get update + +echo '9. Enable the "universe" repositories' +sudo add-apt-repository universe -y + +echo '10. Install PowerShell' +sudo apt-get install -y powershell + +echo '##########################################' +echo '# Exiting Install-LinuxPowerShell.sh #' +echo '##########################################' + +exit 0 diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Install-WindowsPowerShell.ps1 b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Install-WindowsPowerShell.ps1 new file mode 100644 index 0000000000..2ecdce36eb --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployAll/scripts/Install-WindowsPowerShell.ps1 @@ -0,0 +1,43 @@ +Write-Verbose '##############################################' -Verbose +Write-Verbose '# Entering Install-WindowsPowerShell.ps1 #' -Verbose +Write-Verbose '##############################################' -Verbose + +$psVersion = '7.4.4' +$ps7Url = "https://github.com/PowerShell/PowerShell/releases/download/v$psVersion/PowerShell-$psVersion-win-x64.zip" +$downloadFolder = (Get-Location).Path +$downloadLoc = Join-Path $downloadFolder (Split-Path $ps7Url -Leaf) + +if (-not (Test-Path $downloadLoc)) { + Write-Verbose "Download to [$downloadLoc]" -Verbose + (New-Object System.Net.WebClient).DownloadFile($ps7Url, $downloadLoc) + Unblock-File $downloadLoc + Write-Verbose 'Downloaded' -Verbose +} else { + Write-Verbose "Already downloaded to [$downloadLoc]" -Verbose +} + +$installLoc = "$env:ProgramFiles\PowerShell\7" + +if (-not (Test-Path $installLoc)) { + Write-Verbose "Install to [$installLoc]" -Verbose + Expand-Archive -Path $downloadLoc -DestinationPath $installLoc + Write-Verbose 'Installed' -Verbose +} else { + Write-Verbose "Already installed in [$installLoc]" -Verbose +} + +if ($Env:PATH -notlike "*$installLoc*") { + Write-Verbose 'Set environment variable' -Verbose + [Environment]::SetEnvironmentVariable('PATH', $Env:PATH + ";$installLoc", [EnvironmentVariableTarget]::Machine) + $env:Path += ";$installLoc" + Write-Verbose 'Environment variable set' -Verbose +} else { + Write-Verbose 'Environment variable already set' -Verbose +} + +Write-Verbose 'Try run PS-Core' -Verbose +pwsh -Command 'Write-Host "Hello from the inside"' + +Write-Verbose '#############################################' -Verbose +Write-Verbose '# Exiting Install-WindowsPowerShell.ps1 #' -Verbose +Write-Verbose '#############################################' -Verbose diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep new file mode 100644 index 0000000000..be25388fde --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/dependencies.bicep @@ -0,0 +1,251 @@ +targetScope = 'subscription' + +@description('Required. The name of the Resource Group.') +param resourceGroupName string + +@description('Required. The name of the Resource Group to deploy the Image Template resources into.') +param imageTemplateResourceGroupName string + +// User Assigned Identity (MSI) Parameters +@description('Required. The name of the Managed Identity used by deployment scripts.') +param deploymentScriptManagedIdentityName string + +@description('Required. The name of the Managed Identity used by the Azure Image Builder.') +param imageManagedIdentityName string + +// Azure Compute Gallery Parameters +@description('Required. The name of the Azure Compute Gallery.') +param computeGalleryName string + +// Storage Account Parameters +@description('Required. The name of the storage account. Only needed if you want to upload scripts to be used during image baking.') +param assetsStorageAccountName string + +@description('Required. The name of the storage account.') +param deploymentScriptStorageAccountName string + +// Virtual Network Parameters +@description('Required. The name of the Virtual Network.') +param virtualNetworkName string + +// Shared Parameters +@description('Optional. The location to deploy into.') +param location string = deployment().location + +var addressPrefix = '10.0.0.0/16' + +// The Image Definitions in the Azure Compute Gallery +var computeGalleryImageDefinitionsVar = [ + { + hyperVGeneration: 'V2' + name: 'sid-linux' + osType: 'Linux' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' + } +] +var assetsStorageAccountContainerName = 'aibscripts' + +// Role required for deployment script to be able to use a storage account via private networking +resource storageFileDataPrivilegedContributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Priveleged Contributor + scope: tenant() +} +resource contributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + scope: tenant() +} + +// Resource Groups +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location +} + +// Always deployed as both an infra element & needed as a staging resource group for image building +module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.4.0' = { + name: '${deployment().name}-image-rg' + params: { + name: imageTemplateResourceGroupName + location: location + } +} + +// User Assigned Identity (MSI) +module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { + name: '${deployment().name}-ds-msi' + scope: rg + params: { + name: deploymentScriptManagedIdentityName + location: location + } +} + +module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { + name: '${deployment().name}-image-msi' + scope: rg + params: { + name: imageManagedIdentityName + location: location + } +} + +// MSI Subscription contributor assignment +resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, imageManagedIdentityName, contributorRole.id) + properties: { + principalId: imageMSI.outputs.principalId + roleDefinitionId: contributorRole.id + principalType: 'ServicePrincipal' + } +} + +// Azure Compute Gallery +module azureComputeGallery 'br/public:avm/res/compute/gallery:0.7.0' = { + name: '${deployment().name}-acg' + scope: rg + params: { + name: computeGalleryName + images: computeGalleryImageDefinitionsVar + location: location + } +} + +// Image Template Virtual Network +module vnet 'br/public:avm/res/network/virtual-network:0.4.0' = { + name: '${deployment().name}-vnet' + scope: rg + params: { + name: virtualNetworkName + addressPrefixes: [ + addressPrefix + ] + subnets: [ + { + name: 'subnet-it' + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET + serviceEndpoints: [ + 'Microsoft.Storage' + ] + } + { + name: 'subnet-ds' + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET - temp + serviceEndpoints: [ + 'Microsoft.Storage' + ] + delegation: 'Microsoft.ContainerInstance/containerGroups' + } + ] + location: location + } +} + +// Assets Storage Account +module assetsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${deployment().name}-files-sa' + scope: rg + params: { + name: assetsStorageAccountName + allowSharedKeyAccess: false // Keys not needed if MSI is granted access + location: location + networkAcls: { + defaultAction: 'Allow' + } + blobServices: { + containers: [ + { + name: assetsStorageAccountContainerName + publicAccess: 'None' + roleAssignments: [ + { + // Allow Infra MSI to access storage account container to upload files - DO NOT REMOVE + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: dsMsi.outputs.principalId + principalType: 'ServicePrincipal' + } + { + // Allow image MSI to access storage account container to read files - DO NOT REMOVE + roleDefinitionIdOrName: 'Storage Blob Data Reader' + principalId: imageMSI.outputs.principalId + principalType: 'ServicePrincipal' + } + ] + } + ] + } + } +} + +// Deployment scripts & their storage account +module dsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${deployment().name}-ds-sa' + scope: rg + params: { + name: deploymentScriptStorageAccountName + allowSharedKeyAccess: true // May not be disabled to allow deployment script to access storage account files + roleAssignments: [ + { + // Allow MSI to leverage the storage account for private networking of container instance + // ref: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-bicep#access-private-virtual-network + roleDefinitionIdOrName: storageFileDataPrivilegedContributorRole.id // Storage File Data Priveleged Contributor + principalId: dsMsi.outputs.principalId + principalType: 'ServicePrincipal' + } + ] + location: location + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + // Allow deployment script to use storage account for private networking of container instance + action: 'Allow' + id: vnet.outputs.subnetResourceIds[1] // subnet-ds + } + ] + } + } +} + +@description('The image definitions used in the Azure Compute Gallery.') +output computeGalleryImageDefinitions array = computeGalleryImageDefinitionsVar + +@description('The name of the created Resource Group.') +output resourceGroupName string = rg.name + +@description('The name of the created Azure Compute Gallery') +output computeGalleryName string = azureComputeGallery.outputs.name + +@description('The name of the created Virtual Network') +output virtualNetworkName string = vnet.outputs.name + +@description('The name of the Storage Account Container hosting the customization files used by the Azure Image Builder.') +output assetsStorageAccountContainerName string = assetsStorageAccountContainerName + +@description('The name of the create Storage Account hosting the customization files used by the Azure Image Builder.') +output assetsStorageAccountName string = assetsStorageAccount.outputs.name + +@description('The name of the User-Assigned-Identity used by the Deployment Scripts.') +output deploymentScriptManagedIdentityName string = dsMsi.outputs.name + +@description('The name of the Storage Account used by the Deployment Scripts.') +output deploymentScriptStorageAccountName string = dsStorageAccount.outputs.name + +@description('The name of the subnet used by the Azure Image Builder.') +output imageSubnetName string = last(split(vnet.outputs.subnetResourceIds[0], '/')) + +@description('The name of the subnet used by the Deployment Scripts.') +output deploymentScriptSubnetName string = last(split(vnet.outputs.subnetResourceIds[1], '/')) + +@description('The name of the User-Assigned-Identity used by the Azure Image Builder.') +output imageManagedIdentityName string = imageMSI.outputs.name + +@description('The name of the Resource Group used by the Azure Image Builder.') +output imageTemplateResourceGroupName string = imageTemplateRg.outputs.name diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/main.test.bicep new file mode 100644 index 0000000000..849d005a0e --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/main.test.bicep @@ -0,0 +1,90 @@ +targetScope = 'subscription' + +metadata name = 'Deploying only the assets & image' +metadata description = 'This instance deploys the module with the conditions set up to only update the assets on the assets storage account and build the image, assuming all dependencies are setup.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.azureimagebuilder-${serviceShort}-rg' + +@description('Optional. The location to deploy resource group to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apvmiaiboaai' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module nestedDependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + computeGalleryName: 'dep${namePrefix}gal${serviceShort}' + deploymentScriptManagedIdentityName: 'dep-${namePrefix}-ds-msi-${serviceShort}' + imageManagedIdentityName: 'dep-${namePrefix}-it-msi-${serviceShort}' + resourceGroupName: resourceGroupName + imageTemplateResourceGroupName: '${resourceGroupName}-image-build' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + deploymentScriptStorageAccountName: 'dep${namePrefix}dsst${serviceShort}' + assetsStorageAccountName: 'dep${namePrefix}ast${serviceShort}' + location: resourceLocation + } +} + +///////////////////////////// +// Template Deployment // +///////////////////////////// +var exampleScriptName = 'exampleScript.sh' + +// No idempotency test as we don't want to bake 2 images +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + deploymentsToPerform: 'Only assets & image' + resourceGroupName: nestedDependencies.outputs.resourceGroupName + location: resourceLocation + computeGalleryName: nestedDependencies.outputs.computeGalleryName + computeGalleryImageDefinitionName: nestedDependencies.outputs.computeGalleryImageDefinitions[0].name + computeGalleryImageDefinitions: nestedDependencies.outputs.computeGalleryImageDefinitions + virtualNetworkName: nestedDependencies.outputs.virtualNetworkName + assetsStorageAccountContainerName: nestedDependencies.outputs.assetsStorageAccountContainerName + assetsStorageAccountName: nestedDependencies.outputs.assetsStorageAccountName + deploymentScriptManagedIdentityName: nestedDependencies.outputs.deploymentScriptManagedIdentityName + deploymentScriptStorageAccountName: nestedDependencies.outputs.deploymentScriptStorageAccountName + deploymentScriptSubnetName: nestedDependencies.outputs.deploymentScriptSubnetName + imageManagedIdentityName: nestedDependencies.outputs.imageManagedIdentityName + imageSubnetName: nestedDependencies.outputs.imageSubnetName + imageTemplateResourceGroupName: nestedDependencies.outputs.imageTemplateResourceGroupName + imageTemplateCustomizationSteps: [ + { + type: 'Shell' + name: 'Example script' + scriptUri: 'https://${nestedDependencies.outputs.assetsStorageAccountName}.blob.${az.environment().suffixes.storage}/${nestedDependencies.outputs.assetsStorageAccountContainerName}/${exampleScriptName}' + } + ] + imageTemplateImageSource: { + type: 'PlatformImage' + publisher: 'canonical' + offer: 'ubuntu-24_04-lts' + sku: 'server' + version: 'latest' + } + storageAccountFilesToUpload: [ + { + name: exampleScriptName + value: loadTextContent('scripts/${exampleScriptName}') + } + ] + } +} diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/scripts/exampleScript.sh b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/scripts/exampleScript.sh new file mode 100644 index 0000000000..22cd6c612f --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyAssetsAndImage/scripts/exampleScript.sh @@ -0,0 +1,4 @@ +echo '###############################################' +echo '# Hey there. Just checking the place out. #' +echo '###############################################' + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep new file mode 100644 index 0000000000..720941b1e9 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyBase/main.test.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +metadata name = 'Deploying only the base services' +metadata description = 'This instance deploys the module with the conditions set up to only deploy the base resources, that is everything but the image.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.azureimagebuilder-${serviceShort}-rg' + +@description('Optional. The location to deploy resource group to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apvmiaibob' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +///////////////////////////// +// Template Deployment // +///////////////////////////// +var computeGalleryImageDefinitionName = 'sid-linux' + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + deploymentsToPerform: 'Only base' + resourceGroupName: resourceGroupName + location: resourceLocation + assetsStorageAccountName: 'st${namePrefix}${serviceShort}' + imageManagedIdentityName: 'msi-it-${namePrefix}-${serviceShort}' + computeGalleryName: 'gal${namePrefix}${serviceShort}' + computeGalleryImageDefinitionName: computeGalleryImageDefinitionName + computeGalleryImageDefinitions: [ + { + hyperVGeneration: 'V2' + name: computeGalleryImageDefinitionName + osType: 'Linux' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' + } + ] + imageTemplateImageSource: { + type: 'PlatformImage' + publisher: 'canonical' + offer: 'ubuntu-24_04-lts' + sku: 'server' + version: 'latest' + } + } + } +] diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep new file mode 100644 index 0000000000..7a4eb4a7c3 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/dependencies.bicep @@ -0,0 +1,295 @@ +targetScope = 'subscription' + +@description('Required. The name of the Resource Group.') +param resourceGroupName string + +@description('Required. The name of the Resource Group to deploy the Image Template resources into.') +param imageTemplateResourceGroupName string + +// User Assigned Identity (MSI) Parameters +@description('Required. The name of the Managed Identity used by deployment scripts.') +param deploymentScriptManagedIdentityName string + +@description('Required. The name of the Managed Identity used by the Azure Image Builder.') +param imageManagedIdentityName string + +// Azure Compute Gallery Parameters +@description('Required. The name of the Azure Compute Gallery.') +param computeGalleryName string + +// Storage Account Parameters +@description('Required. The name of the storage account. Only needed if you want to upload scripts to be used during image baking.') +param assetsStorageAccountName string + +@description('Required. The name of the storage account.') +param deploymentScriptStorageAccountName string + +@description('Required. The name of the Deployment Script to the Storage Upload.') +param storageDeploymentScriptName string + +// Virtual Network Parameters +@description('Required. The name of the Virtual Network.') +param virtualNetworkName string + +// Shared Parameters +@description('Optional. The location to deploy into.') +param location string = deployment().location + +var exampleScriptName = 'exampleScript.sh' +var addressPrefix = '10.0.0.0/16' + +// The Image Definitions in the Azure Compute Gallery +var computeGalleryImageDefinitionsVar = [ + { + hyperVGeneration: 'V2' + name: 'sid-linux' + osType: 'Linux' + identifier: { + publisher: 'devops' + offer: 'devops_linux' + sku: 'devops_linux_az' + } + osState: 'Generalized' + } +] +var assetsStorageAccountContainerName = 'aibscripts' + +// Role required for deployment script to be able to use a storage account via private networking +resource storageFileDataPrivilegedContributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '69566ab7-960f-475b-8e7c-b3118f30c6bd' // Storage File Data Priveleged Contributor + scope: tenant() +} +resource contributorRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + scope: tenant() +} + +// Resource Groups +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location +} + +// Always deployed as both an infra element & needed as a staging resource group for image building +module imageTemplateRg 'br/public:avm/res/resources/resource-group:0.4.0' = { + name: '${deployment().name}-image-rg' + params: { + name: imageTemplateResourceGroupName + location: location + } +} + +// User Assigned Identity (MSI) +module dsMsi 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { + name: '${deployment().name}-ds-msi' + scope: rg + params: { + name: deploymentScriptManagedIdentityName + location: location + } +} + +module imageMSI 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { + name: '${deployment().name}-image-msi' + scope: rg + params: { + name: imageManagedIdentityName + location: location + } +} + +// MSI Subscription contributor assignment +resource imageMSI_rbac 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().subscriptionId, imageManagedIdentityName, contributorRole.id) + properties: { + principalId: imageMSI.outputs.principalId + roleDefinitionId: contributorRole.id + principalType: 'ServicePrincipal' + } +} + +// Azure Compute Gallery +module azureComputeGallery 'br/public:avm/res/compute/gallery:0.7.0' = { + name: '${deployment().name}-acg' + scope: rg + params: { + name: computeGalleryName + images: computeGalleryImageDefinitionsVar + location: location + } +} + +// Image Template Virtual Network +module vnet 'br/public:avm/res/network/virtual-network:0.4.0' = { + name: '${deployment().name}-vnet' + scope: rg + params: { + name: virtualNetworkName + addressPrefixes: [ + addressPrefix + ] + subnets: [ + { + name: 'subnet-it' + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET + serviceEndpoints: [ + 'Microsoft.Storage' + ] + } + { + name: 'subnet-ds' + addressPrefix: cidrSubnet(addressPrefix, 24, 1) + privateLinkServiceNetworkPolicies: 'Disabled' // Required if using Azure Image Builder with existing VNET - temp + serviceEndpoints: [ + 'Microsoft.Storage' + ] + delegation: 'Microsoft.ContainerInstance/containerGroups' + } + ] + location: location + } +} + +// Assets Storage Account +module assetsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${deployment().name}-files-sa' + scope: rg + params: { + name: assetsStorageAccountName + allowSharedKeyAccess: false // Keys not needed if MSI is granted access + location: location + networkAcls: { + defaultAction: 'Allow' + } + blobServices: { + containers: [ + { + name: assetsStorageAccountContainerName + publicAccess: 'None' + roleAssignments: [ + { + // Allow Infra MSI to access storage account container to upload files - DO NOT REMOVE + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalId: dsMsi.outputs.principalId + principalType: 'ServicePrincipal' + } + { + // Allow image MSI to access storage account container to read files - DO NOT REMOVE + roleDefinitionIdOrName: 'Storage Blob Data Reader' + principalId: imageMSI.outputs.principalId + principalType: 'ServicePrincipal' + } + ] + } + ] + } + } +} + +// Deployment scripts & their storage account +module dsStorageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${deployment().name}-ds-sa' + scope: rg + params: { + name: deploymentScriptStorageAccountName + allowSharedKeyAccess: true // May not be disabled to allow deployment script to access storage account files + roleAssignments: [ + { + // Allow MSI to leverage the storage account for private networking of container instance + // ref: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-script-bicep#access-private-virtual-network + roleDefinitionIdOrName: storageFileDataPrivilegedContributorRole.id // Storage File Data Priveleged Contributor + principalId: dsMsi.outputs.principalId + principalType: 'ServicePrincipal' + } + ] + location: location + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + virtualNetworkRules: [ + { + // Allow deployment script to use storage account for private networking of container instance + action: 'Allow' + id: vnet.outputs.subnetResourceIds[1] // subnet-ds + } + ] + } + } +} + +// Upload storage account files +module storageAccount_upload 'br/public:avm/res/resources/deployment-script:0.4.0' = { + name: '${deployment().name}-storage-upload-ds' + scope: resourceGroup(resourceGroupName) + params: { + name: storageDeploymentScriptName + kind: 'AzurePowerShell' + azPowerShellVersion: '12.0' + managedIdentities: { + userAssignedResourcesIds: [ + resourceId( + subscription().subscriptionId, + resourceGroupName, + 'Microsoft.ManagedIdentity/userAssignedIdentities', + deploymentScriptManagedIdentityName + ) + ] + } + scriptContent: loadTextContent('../../../../../../utilities/e2e-template-assets/scripts/Set-StorageContainerContentByEnvVar.ps1') + environmentVariables: [ + { + name: '__SCRIPT__${replace(replace(exampleScriptName, '-', '__'), '.', '_') }' // May only be alphanumeric characters & underscores. The upload will replace '_' with '.' and '__' with '-'. E.g., Install__LinuxPowerShell_sh will be Install-LinuxPowerShell.sh + value: loadTextContent('scripts/${exampleScriptName}') + } + ] + + arguments: ' -StorageAccountName "${assetsStorageAccountName}" -TargetContainer "${assetsStorageAccountContainerName}"' + timeout: 'PT30M' + cleanupPreference: 'Always' + location: location + storageAccountResourceId: dsStorageAccount.outputs.resourceId + subnetResourceIds: [ + vnet.outputs.subnetResourceIds[1] // subnet-ds + ] + } +} + +@description('The image definitions used in the Azure Compute Gallery.') +output computeGalleryImageDefinitions array = computeGalleryImageDefinitionsVar + +@description('The name of the created Resource Group.') +output resourceGroupName string = rg.name + +@description('The name of the created Azure Compute Gallery') +output computeGalleryName string = azureComputeGallery.outputs.name + +@description('The name of the created Virtual Network') +output virtualNetworkName string = vnet.outputs.name + +@description('The name of the Storage Account Container hosting the customization files used by the Azure Image Builder.') +output assetsStorageAccountContainerName string = assetsStorageAccountContainerName + +@description('The name of the create Storage Account hosting the customization files used by the Azure Image Builder.') +output assetsStorageAccountName string = assetsStorageAccount.outputs.name + +@description('The name of the User-Assigned-Identity used by the Deployment Scripts.') +output deploymentScriptManagedIdentityName string = dsMsi.outputs.name + +@description('The name of the Storage Account used by the Deployment Scripts.') +output deploymentScriptStorageAccountName string = dsStorageAccount.outputs.name + +@description('The name of the subnet used by the Azure Image Builder.') +output imageSubnetName string = last(split(vnet.outputs.subnetResourceIds[0], '/')) + +@description('The name of the subnet used by the Deployment Scripts.') +output deploymentScriptSubnetName string = last(split(vnet.outputs.subnetResourceIds[1], '/')) + +@description('The name of the User-Assigned-Identity used by the Azure Image Builder.') +output imageManagedIdentityName string = imageMSI.outputs.name + +@description('The name of the Resource Group used by the Azure Image Builder.') +output imageTemplateResourceGroupName string = imageTemplateRg.outputs.name + +@description('The name of the script uploaded to the Assets Storage Account to use in the Azure Image Builder customization steps.') +output exampleScriptName string = exampleScriptName diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/main.test.bicep b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/main.test.bicep new file mode 100644 index 0000000000..c777fa31da --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'Deploying only the image' +metadata description = 'This instance deploys the module with the conditions set up to only deploy and bake the image, assuming all dependencies are setup.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-virtualmachineimages.azureimagebuilder-${serviceShort}-rg' + +@description('Optional. The location to deploy resource group to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'apvmiaiboi' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +@description('Generated. Do not provide a value! This date value is used to generate a SAS token to access the modules.') +param baseTime string = utcNow() + +var formattedTime = replace(replace(replace(baseTime, ':', ''), '-', ''), ' ', '') + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +module nestedDependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + // managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + computeGalleryName: 'dep${namePrefix}gal${serviceShort}' + deploymentScriptManagedIdentityName: 'dep-${namePrefix}-ds-msi-${serviceShort}' + imageManagedIdentityName: 'dep-${namePrefix}-it-msi-${serviceShort}' + resourceGroupName: resourceGroupName + imageTemplateResourceGroupName: '${resourceGroupName}-image-build' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + deploymentScriptStorageAccountName: 'dep${namePrefix}dsst${serviceShort}' + storageDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}-${formattedTime}' + assetsStorageAccountName: 'dep${namePrefix}ast${serviceShort}' + location: resourceLocation + } +} + +///////////////////////////// +// Template Deployment // +///////////////////////////// + +// No idempotency test as we don't want to bake 2 images +module testDeployment '../../../main.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + deploymentsToPerform: 'Only image' + resourceGroupName: nestedDependencies.outputs.resourceGroupName + location: resourceLocation + computeGalleryName: nestedDependencies.outputs.computeGalleryName + computeGalleryImageDefinitions: nestedDependencies.outputs.computeGalleryImageDefinitions + computeGalleryImageDefinitionName: nestedDependencies.outputs.computeGalleryImageDefinitions[0].name + virtualNetworkName: nestedDependencies.outputs.virtualNetworkName + deploymentScriptManagedIdentityName: nestedDependencies.outputs.deploymentScriptManagedIdentityName + deploymentScriptStorageAccountName: nestedDependencies.outputs.deploymentScriptStorageAccountName + deploymentScriptSubnetName: nestedDependencies.outputs.deploymentScriptSubnetName + imageManagedIdentityName: nestedDependencies.outputs.imageManagedIdentityName + imageSubnetName: nestedDependencies.outputs.imageSubnetName + imageTemplateResourceGroupName: nestedDependencies.outputs.imageTemplateResourceGroupName + imageTemplateImageSource: { + type: 'PlatformImage' + publisher: 'canonical' + offer: 'ubuntu-24_04-lts' + sku: 'server' + version: 'latest' + } + imageTemplateCustomizationSteps: [ + { + type: 'Shell' + name: 'Example script' + scriptUri: 'https://${nestedDependencies.outputs.assetsStorageAccountName}.blob.${az.environment().suffixes.storage}/${nestedDependencies.outputs.assetsStorageAccountContainerName}/${nestedDependencies.outputs.exampleScriptName}' + } + ] + } +} diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/scripts/exampleScript.sh b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/scripts/exampleScript.sh new file mode 100644 index 0000000000..22cd6c612f --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/tests/e2e/deployOnlyImage/scripts/exampleScript.sh @@ -0,0 +1,4 @@ +echo '###############################################' +echo '# Hey there. Just checking the place out. #' +echo '###############################################' + diff --git a/avm/ptn/virtual-machine-images/azure-image-builder/version.json b/avm/ptn/virtual-machine-images/azure-image-builder/version.json new file mode 100644 index 0000000000..83083db694 --- /dev/null +++ b/avm/ptn/virtual-machine-images/azure-image-builder/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/res/aad/domain-service/README.md b/avm/res/aad/domain-service/README.md index 9aa32399c5..c7f0fbcee7 100644 --- a/avm/res/aad/domain-service/README.md +++ b/avm/res/aad/domain-service/README.md @@ -99,7 +99,7 @@ module domainService 'br/public:avm/res/aad/domain-service:' = {
    -via JSON Parameter file +via JSON parameters file ```json { @@ -186,6 +186,65 @@ module domainService 'br/public:avm/res/aad/domain-service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/aad/domain-service:' + +// Required parameters +param domainName = 'onmicrosoft.com' +// Non-required parameters +param additionalRecipients = [ + '@noreply.github.com' +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param externalAccess = 'Enabled' +param ldaps = 'Enabled' +param location = '' +param lock = { + kind: 'None' + name: 'myCustomLockName' +} +param name = 'aaddswaf001' +param pfxCertificate = '' +param pfxCertificatePassword = '' +param replicaSets = [ + { + location: 'NorthEurope' + subnetId: '' + } +] +param sku = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -645,6 +704,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/alerts-management/action-rule/README.md b/avm/res/alerts-management/action-rule/README.md index 72c9e58af6..5bb136e59b 100644 --- a/avm/res/alerts-management/action-rule/README.md +++ b/avm/res/alerts-management/action-rule/README.md @@ -56,7 +56,7 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/alerts-management/action-rule:' + +// Required parameters +param name = 'aprmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -232,7 +248,7 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -398,6 +414,150 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/alerts-management/action-rule:' + +// Required parameters +param name = 'aprmax001' +// Non-required parameters +param actions = [ + { + actionGroupIds: [ + '' + ] + actionType: 'AddActionGroups' + } +] +param aprDescription = 'Test deployment of the module with the max set of parameters.' +param conditions = [ + { + field: 'AlertContext' + operator: 'NotEquals' + values: [ + 'myAlertContext' + ] + } + { + field: 'AlertRuleId' + operator: 'Equals' + values: [ + '' + ] + } + { + field: 'AlertRuleName' + operator: 'Equals' + values: [ + '' + ] + } + { + field: 'Description' + operator: 'Contains' + values: [ + 'myAlertRuleDescription' + ] + } + { + field: 'MonitorService' + operator: 'Equals' + values: [ + 'ActivityLog Administrative' + ] + } + { + field: 'MonitorCondition' + operator: 'Equals' + values: [ + 'Fired' + ] + } + { + field: 'TargetResourceType' + operator: 'DoesNotContain' + values: [ + 'myAlertResourceType' + ] + } + { + field: 'TargetResource' + operator: 'Equals' + values: [ + 'myAlertResource1' + 'myAlertResource2' + ] + } + { + field: 'TargetResourceGroup' + operator: 'Equals' + values: [ + '' + ] + } + { + field: 'Severity' + operator: 'Equals' + values: [ + 'Sev0' + 'Sev1' + 'Sev2' + 'Sev3' + 'Sev4' + ] + } + { + field: 'SignalType' + operator: 'Equals' + values: [ + 'Health' + 'Log' + 'Metric' + 'Unknown' + ] + } +] +param enabled = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'a66da6bc-b3ee-484e-9bdb-9294938bb327' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scopes = [ + '' +] +param tags = { + 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. @@ -436,7 +596,7 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -476,6 +636,34 @@ module actionRule 'br/public:avm/res/alerts-management/action-rule:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/alerts-management/action-rule:' + +// Required parameters +param name = 'aprwaf001' +// Non-required parameters +param actions = [ + { + actionGroupIds: [ + '' + ] + actionType: 'AddActionGroups' + } +] +param aprDescription = 'Test deployment of the module with the waf aligned set of parameters.' +param location = '' +param scopes = [ + '' +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -603,6 +791,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/analysis-services/server/README.md b/avm/res/analysis-services/server/README.md index 18ad72dda3..746d2e0701 100644 --- a/avm/res/analysis-services/server/README.md +++ b/avm/res/analysis-services/server/README.md @@ -62,7 +62,7 @@ module server 'br/public:avm/res/analysis-services/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,22 @@ module server 'br/public:avm/res/analysis-services/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/analysis-services/server:' + +// Required parameters +param name = 'assmin' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -172,7 +188,7 @@ module server 'br/public:avm/res/analysis-services/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -270,6 +286,84 @@ module server 'br/public:avm/res/analysis-services/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/analysis-services/server:' + +// Required parameters +param name = 'assmax' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'Engine' + } + { + category: 'Service' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallSettings = { + enablePowerBIService: true + firewallRules: [ + { + firewallRuleName: 'AllowFromAll' + rangeEnd: '255.255.255.255' + rangeStart: '0.0.0.0' + } + ] +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '0a657697-dd80-427e-b1bc-7970ab74f937' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 1 +param skuName = 'S0' +param tags = { + 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. @@ -339,7 +433,7 @@ module server 'br/public:avm/res/analysis-services/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +510,65 @@ module server 'br/public:avm/res/analysis-services/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/analysis-services/server:' + +// Required parameters +param name = 'asswaf' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'Engine' + } + { + category: 'Service' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallSettings = { + enablePowerBIService: true + firewallRules: [ + { + firewallRuleName: 'AllowFromAll' + rangeEnd: '255.255.255.255' + rangeStart: '0.0.0.0' + } + ] +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param skuCapacity = 1 +param skuName = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -669,6 +822,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/api-management/service/README.md b/avm/res/api-management/service/README.md index fa41e81140..42c1636201 100644 --- a/avm/res/api-management/service/README.md +++ b/avm/res/api-management/service/README.md @@ -80,7 +80,7 @@ module service 'br/public:avm/res/api-management/service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -111,6 +111,25 @@ module service 'br/public:avm/res/api-management/service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apiscon001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +param sku = 'Consumption' +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -139,7 +158,7 @@ module service 'br/public:avm/res/api-management/service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -167,6 +186,24 @@ module service 'br/public:avm/res/api-management/service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apismin001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 3: _Deploying a Developer SKU_ This instance deploys the module using a Developer SKU. @@ -196,7 +233,7 @@ module service 'br/public:avm/res/api-management/service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +264,25 @@ module service 'br/public:avm/res/api-management/service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apisdev001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +param sku = 'Developer' +``` + +
    +

    + ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -290,6 +346,7 @@ module service 'br/public:avm/res/api-management/service:' = { clientId: 'apimclientid' clientRegistrationEndpoint: 'http://localhost' clientSecret: '' + displayName: 'AuthServer1' grantTypes: [ 'authorizationCode' ] @@ -404,6 +461,7 @@ module service 'br/public:avm/res/api-management/service:' = { } ] approvalRequired: false + displayName: 'Starter' groups: [ { name: 'developers' @@ -436,6 +494,7 @@ module service 'br/public:avm/res/api-management/service:' = { subnetResourceId: '' subscriptions: [ { + displayName: 'testArmSubscriptionAllApis' name: 'testArmSubscriptionAllApis' scope: '/apis' } @@ -455,7 +514,7 @@ module service 'br/public:avm/res/api-management/service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -525,6 +584,7 @@ module service 'br/public:avm/res/api-management/service:' = { "clientId": "apimclientid", "clientRegistrationEndpoint": "http://localhost", "clientSecret": "", + "displayName": "AuthServer1", "grantTypes": [ "authorizationCode" ], @@ -663,6 +723,7 @@ module service 'br/public:avm/res/api-management/service:' = { } ], "approvalRequired": false, + "displayName": "Starter", "groups": [ { "name": "developers" @@ -703,6 +764,7 @@ module service 'br/public:avm/res/api-management/service:' = { "subscriptions": { "value": [ { + "displayName": "testArmSubscriptionAllApis", "name": "testArmSubscriptionAllApis", "scope": "/apis" } @@ -725,6 +787,227 @@ module service 'br/public:avm/res/api-management/service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apismax001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param additionalLocations = [ + { + disableGateway: false + location: '' + publicIpAddressId: '' + sku: { + capacity: 1 + name: 'Premium' + } + virtualNetworkConfiguration: { + subnetResourceId: '' + } + } +] +param apiDiagnostics = [ + { + apiName: 'echo-api' + loggerName: 'logger' + metrics: true + name: 'applicationinsights' + } +] +param apis = [ + { + apiVersionSet: { + name: 'echo-version-set' + properties: { + description: 'echo-version-set' + displayName: 'echo-version-set' + versioningScheme: 'Segment' + } + } + displayName: 'Echo API' + name: 'echo-api' + path: 'echo' + serviceUrl: 'http://echoapi.cloudapp.net/api' + } +] +param authorizationServers = { + secureList: [ + { + authorizationEndpoint: '' + clientId: 'apimclientid' + clientRegistrationEndpoint: 'http://localhost' + clientSecret: '' + displayName: 'AuthServer1' + grantTypes: [ + 'authorizationCode' + ] + name: 'AuthServer1' + tokenEndpoint: '' + } + ] +} +param backends = [ + { + name: 'backend' + tls: { + validateCertificateChain: false + validateCertificateName: false + } + url: 'http://echoapi.cloudapp.net/api' + } +] +param caches = [ + { + connectionString: 'connectionstringtest' + name: 'westeurope' + useFromLocation: 'westeurope' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param identityProviders = [ + { + allowedTenants: [ + 'mytenant.onmicrosoft.com' + ] + authority: '' + clientId: 'apimClientid' + clientLibrary: 'MSAL-2' + clientSecret: 'apimSlientSecret' + name: 'aad' + signinTenant: 'mytenant.onmicrosoft.com' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param loggers = [ + { + credentials: { + instrumentationKey: '' + } + description: 'Logger to Azure Application Insights' + isBuffered: false + loggerType: 'applicationInsights' + name: 'logger' + resourceId: '' + } +] +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param namedValues = [ + { + displayName: 'apimkey' + name: 'apimkey' + secret: true + } +] +param policies = [ + { + format: 'xml' + value: ' ' + } +] +param portalsettings = [ + { + name: 'signin' + properties: { + enabled: false + } + } + { + name: 'signup' + properties: { + enabled: false + termsOfService: { + consentRequired: false + enabled: false + } + } + } +] +param products = [ + { + apis: [ + { + name: 'echo-api' + } + ] + approvalRequired: false + displayName: 'Starter' + groups: [ + { + name: 'developers' + } + ] + name: 'Starter' + subscriptionRequired: false + } +] +param publicIpAddressResourceId = '' +param roleAssignments = [ + { + name: '6352c3e3-ac6b-43d5-ac43-1077ff373721' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param subnetResourceId = '' +param subscriptions = [ + { + displayName: 'testArmSubscriptionAllApis' + name: 'testArmSubscriptionAllApis' + scope: '/apis' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkType = 'Internal' +``` + +
    +

    + ### Example 5: _Deploying an APIM v2 sku_ This instance deploys the module using a v2 SKU. @@ -754,7 +1037,7 @@ module service 'br/public:avm/res/api-management/service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -785,6 +1068,25 @@ module service 'br/public:avm/res/api-management/service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apisv2s001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param location = '' +param sku = 'BasicV2' +``` + +
    +

    + ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -837,6 +1139,7 @@ module service 'br/public:avm/res/api-management/service:' = { clientId: 'apimClientid' clientRegistrationEndpoint: 'https://localhost' clientSecret: '' + displayName: 'AuthServer1' grantTypes: [ 'authorizationCode' ] @@ -973,6 +1276,7 @@ module service 'br/public:avm/res/api-management/service:' = { ] subscriptions: [ { + displayName: 'testArmSubscriptionAllApis' name: 'testArmSubscriptionAllApis' scope: '/apis' } @@ -991,7 +1295,7 @@ module service 'br/public:avm/res/api-management/service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1048,6 +1352,7 @@ module service 'br/public:avm/res/api-management/service:' = { "clientId": "apimClientid", "clientRegistrationEndpoint": "https://localhost", "clientSecret": "", + "displayName": "AuthServer1", "grantTypes": [ "authorizationCode" ], @@ -1212,6 +1517,7 @@ module service 'br/public:avm/res/api-management/service:' = { "subscriptions": { "value": [ { + "displayName": "testArmSubscriptionAllApis", "name": "testArmSubscriptionAllApis", "scope": "/apis" } @@ -1231,6 +1537,204 @@ module service 'br/public:avm/res/api-management/service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/api-management/service:' + +// Required parameters +param name = 'apiswaf001' +param publisherEmail = 'apimgmt-noreply@mail.windowsazure.com' +param publisherName = 'az-amorg-x-001' +// Non-required parameters +param additionalLocations = [ + { + disableGateway: false + location: 'westus' + sku: { + capacity: 1 + name: 'Premium' + } + } +] +param apis = [ + { + apiVersionSet: { + name: 'echo-version-set' + properties: { + description: 'An echo API version set' + displayName: 'Echo version set' + versioningScheme: 'Segment' + } + } + description: 'An echo API service' + displayName: 'Echo API' + name: 'echo-api' + path: 'echo' + serviceUrl: 'https://echoapi.cloudapp.net/api' + } +] +param authorizationServers = { + secureList: [ + { + authorizationEndpoint: '' + clientId: 'apimClientid' + clientRegistrationEndpoint: 'https://localhost' + clientSecret: '' + displayName: 'AuthServer1' + grantTypes: [ + 'authorizationCode' + ] + name: 'AuthServer1' + tokenEndpoint: '' + } + ] +} +param backends = [ + { + name: 'backend' + tls: { + validateCertificateChain: false + validateCertificateName: false + } + url: 'https://echoapi.cloudapp.net/api' + } +] +param caches = [ + { + connectionString: 'connectionstringtest' + name: 'westeurope' + useFromLocation: 'westeurope' + } +] +param customProperties = { + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Protocols.Server.Http2': 'True' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Ssl30': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls10': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls11': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA256': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_GCM_SHA256': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA256': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TripleDes168': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Ssl30': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls10': 'False' + 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls11': 'False' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param identityProviders = [ + { + allowedTenants: [ + 'mytenant.onmicrosoft.com' + ] + authority: '' + clientId: 'apimClientid' + clientLibrary: 'MSAL-2' + clientSecret: '' + name: 'aad' + signinTenant: 'mytenant.onmicrosoft.com' + } +] +param location = '' +param loggers = [ + { + credentials: { + instrumentationKey: '' + } + description: 'Logger to Azure Application Insights' + isBuffered: false + loggerType: 'applicationInsights' + name: 'logger' + resourceId: '' + } +] +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param minApiVersion = '2022-08-01' +param namedValues = [ + { + displayName: 'apimkey' + name: 'apimkey' + secret: true + } +] +param policies = [ + { + format: 'xml' + value: ' ' + } +] +param portalsettings = [ + { + name: 'signin' + properties: { + enabled: false + } + } + { + name: 'signup' + properties: { + enabled: false + termsOfService: { + consentRequired: false + enabled: false + } + } + } +] +param products = [ + { + apis: [ + { + name: 'echo-api' + } + ] + approvalRequired: true + description: 'This is an echo API' + displayName: 'Echo API' + groups: [ + { + name: 'developers' + } + ] + name: 'Starter' + subscriptionRequired: true + terms: 'By accessing or using the services provided by Echo API through Azure API Management, you agree to be bound by these Terms of Use. These terms may be updated from time to time, and your continued use of the services constitutes acceptance of any changes.' + } +] +param subscriptions = [ + { + displayName: 'testArmSubscriptionAllApis' + name: 'testArmSubscriptionAllApis' + scope: '/apis' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1742,6 +2246,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'API Management Developer Portal Content Editor'` + - `'API Management Service Contributor'` + - `'API Management Service Operator Role'` + - `'API Management Service Reader Role'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1917,6 +2431,8 @@ A list of availability zones denoting where the resource needs to come from. Onl ## Notes +The latest version of this module only includes supported versions of the API Management resource. All unsupported versions of API Management have been removed from the related parameters. See the [API Management stv1 platform retirement](!https://learn.microsoft.com/en-us/azure/api-management/breaking-changes/stv1-platform-retirement-august-2024) article for more details. + ### Parameter Usage: `apiManagementServicePolicy`

    diff --git a/avm/res/api-management/service/api-version-set/main.json b/avm/res/api-management/service/api-version-set/main.json index 85639acf5c..061641030c 100644 --- a/avm/res/api-management/service/api-version-set/main.json +++ b/avm/res/api-management/service/api-version-set/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17159723717884761443" + "version": "0.30.23.60470", + "templateHash": "2492486199367242598" }, "name": "API Management Service API Version Sets", "description": "This module deploys an API Management Service API Version Set.", diff --git a/avm/res/api-management/service/api/diagnostics/main.json b/avm/res/api-management/service/api/diagnostics/main.json index 83e2b3a003..6db7e0f400 100644 --- a/avm/res/api-management/service/api/diagnostics/main.json +++ b/avm/res/api-management/service/api/diagnostics/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", diff --git a/avm/res/api-management/service/api/main.json b/avm/res/api-management/service/api/main.json index 970b83350d..a87b3409db 100644 --- a/avm/res/api-management/service/api/main.json +++ b/avm/res/api-management/service/api/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17160750790361326516" + "version": "0.30.23.60470", + "templateHash": "17036957862982683599" }, "name": "API Management Service APIs", "description": "This module deploys an API Management Service API.", @@ -283,8 +283,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2474188503939052987" + "version": "0.30.23.60470", + "templateHash": "5643177447182050438" }, "name": "API Management Service APIs Policies", "description": "This module deploys an API Management Service API Policy.", @@ -430,8 +430,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", diff --git a/avm/res/api-management/service/api/policy/main.json b/avm/res/api-management/service/api/policy/main.json index 6defcce4a3..af5ae11307 100644 --- a/avm/res/api-management/service/api/policy/main.json +++ b/avm/res/api-management/service/api/policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2474188503939052987" + "version": "0.30.23.60470", + "templateHash": "5643177447182050438" }, "name": "API Management Service APIs Policies", "description": "This module deploys an API Management Service API Policy.", diff --git a/avm/res/api-management/service/authorization-server/README.md b/avm/res/api-management/service/authorization-server/README.md index d6996e57a1..234576e93d 100644 --- a/avm/res/api-management/service/authorization-server/README.md +++ b/avm/res/api-management/service/authorization-server/README.md @@ -23,6 +23,7 @@ This module deploys an API Management Service Authorization Server. | [`authorizationEndpoint`](#parameter-authorizationendpoint) | string | OAuth authorization endpoint. See . | | [`clientId`](#parameter-clientid) | securestring | Client or app ID registered with this authorization server. | | [`clientSecret`](#parameter-clientsecret) | securestring | Client or app secret registered with this authorization server. This property will not be filled on 'GET' operations! Use '/listSecrets' POST request to get the value. | +| [`displayName`](#parameter-displayname) | string | API Management Service Authorization Servers name. Must be 1 to 50 characters long. | | [`grantTypes`](#parameter-granttypes) | array | Form of an authorization grant, which the client uses to request the access token. - authorizationCode, implicit, resourceOwnerPassword, clientCredentials. | | [`name`](#parameter-name) | string | Identifier of the authorization server. | @@ -69,6 +70,13 @@ Client or app secret registered with this authorization server. This property wi - Required: Yes - Type: securestring +### Parameter: `displayName` + +API Management Service Authorization Servers name. Must be 1 to 50 characters long. + +- Required: Yes +- Type: string + ### Parameter: `grantTypes` Form of an authorization grant, which the client uses to request the access token. - authorizationCode, implicit, resourceOwnerPassword, clientCredentials. diff --git a/avm/res/api-management/service/authorization-server/main.bicep b/avm/res/api-management/service/authorization-server/main.bicep index 3be6ae0b89..afe57ae5cd 100644 --- a/avm/res/api-management/service/authorization-server/main.bicep +++ b/avm/res/api-management/service/authorization-server/main.bicep @@ -5,6 +5,10 @@ metadata owner = 'Azure/module-maintainers' @description('Required. Identifier of the authorization server.') param name string +@description('Required. API Management Service Authorization Servers name. Must be 1 to 50 characters long.') +@maxLength(50) +param displayName string + @description('Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment.') param apiManagementServiceName string @@ -85,7 +89,7 @@ resource authorizationServer 'Microsoft.ApiManagement/service/authorizationServe bearerTokenSendingMethods: bearerTokenSendingMethods resourceOwnerUsername: resourceOwnerUsername resourceOwnerPassword: resourceOwnerPassword - displayName: name + displayName: displayName clientRegistrationEndpoint: clientRegistrationEndpoint authorizationEndpoint: authorizationEndpoint grantTypes: grantTypes diff --git a/avm/res/api-management/service/authorization-server/main.json b/avm/res/api-management/service/authorization-server/main.json index e966a03d7f..50d0897a93 100644 --- a/avm/res/api-management/service/authorization-server/main.json +++ b/avm/res/api-management/service/authorization-server/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4256977187793378377" + "version": "0.30.23.60470", + "templateHash": "17927787726774417819" }, "name": "API Management Service Authorization Servers", "description": "This module deploys an API Management Service Authorization Server.", @@ -18,6 +18,13 @@ "description": "Required. Identifier of the authorization server." } }, + "displayName": { + "type": "string", + "maxLength": 50, + "metadata": { + "description": "Required. API Management Service Authorization Servers name. Must be 1 to 50 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -154,7 +161,7 @@ "bearerTokenSendingMethods": "[parameters('bearerTokenSendingMethods')]", "resourceOwnerUsername": "[parameters('resourceOwnerUsername')]", "resourceOwnerPassword": "[parameters('resourceOwnerPassword')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "clientRegistrationEndpoint": "[parameters('clientRegistrationEndpoint')]", "authorizationEndpoint": "[parameters('authorizationEndpoint')]", "grantTypes": "[parameters('grantTypes')]", diff --git a/avm/res/api-management/service/backend/main.json b/avm/res/api-management/service/backend/main.json index 2a5ea70d52..c3ae5f49b2 100644 --- a/avm/res/api-management/service/backend/main.json +++ b/avm/res/api-management/service/backend/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2365531440872951056" + "version": "0.30.23.60470", + "templateHash": "14706757128951530017" }, "name": "API Management Service Backends", "description": "This module deploys an API Management Service Backend.", diff --git a/avm/res/api-management/service/cache/main.json b/avm/res/api-management/service/cache/main.json index b66a377833..285f53b0fb 100644 --- a/avm/res/api-management/service/cache/main.json +++ b/avm/res/api-management/service/cache/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3234729148013684780" + "version": "0.30.23.60470", + "templateHash": "2750555671183513052" }, "name": "API Management Service Caches", "description": "This module deploys an API Management Service Cache.", diff --git a/avm/res/api-management/service/identity-provider/main.json b/avm/res/api-management/service/identity-provider/main.json index f9e6cbe086..6768ba8a3e 100644 --- a/avm/res/api-management/service/identity-provider/main.json +++ b/avm/res/api-management/service/identity-provider/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12757169124799431378" + "version": "0.30.23.60470", + "templateHash": "1342690797398622979" }, "name": "API Management Service Identity Providers", "description": "This module deploys an API Management Service Identity Provider.", diff --git a/avm/res/api-management/service/loggers/main.json b/avm/res/api-management/service/loggers/main.json index 9a6b6378bd..7d3305a3cd 100644 --- a/avm/res/api-management/service/loggers/main.json +++ b/avm/res/api-management/service/loggers/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12986610229102962453" + "version": "0.30.23.60470", + "templateHash": "12834599511984803283" }, "name": "API Management Service Loggers", "description": "This module deploys an API Management Service Logger.", diff --git a/avm/res/api-management/service/main.bicep b/avm/res/api-management/service/main.bicep index 1e69199417..37a49b86c0 100644 --- a/avm/res/api-management/service/main.bicep +++ b/avm/res/api-management/service/main.bicep @@ -310,6 +310,7 @@ module service_authorizationServers 'authorization-server/main.bicep' = [ params: { apiManagementServiceName: service.name name: authorizationServer.name + displayName: authorizationServer.displayName authorizationEndpoint: authorizationServer.authorizationEndpoint authorizationMethods: authorizationServer.?authorizationMethods ?? ['GET'] bearerTokenSendingMethods: authorizationServer.?bearerTokenSendingMethods ?? ['authorizationHeader'] @@ -467,6 +468,7 @@ module service_products 'product/main.bicep' = [ for (product, index) in products: { name: '${uniqueString(deployment().name, location)}-Apim-Product-${index}' params: { + displayName: product.displayName apiManagementServiceName: service.name apis: product.?apis ?? [] approvalRequired: product.?approvalRequired ?? false @@ -490,6 +492,7 @@ module service_subscriptions 'subscription/main.bicep' = [ params: { apiManagementServiceName: service.name name: subscription.name + displayName: subscription.displayName allowTracing: subscription.?allowTracing ownerId: subscription.?ownerId primaryKey: subscription.?primaryKey diff --git a/avm/res/api-management/service/main.json b/avm/res/api-management/service/main.json index 64675ab023..fc42a71966 100644 --- a/avm/res/api-management/service/main.json +++ b/avm/res/api-management/service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5150103142771299599" + "version": "0.30.23.60470", + "templateHash": "7676062632439815762" }, "name": "API Management Services", "description": "This module deploys an API Management Service. The default deployment is set to use a Premium SKU to align with Microsoft WAF-aligned best practices. In most cases, non-prod deployments should use a lower-tier SKU.", @@ -791,8 +791,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17160750790361326516" + "version": "0.30.23.60470", + "templateHash": "17036957862982683599" }, "name": "API Management Service APIs", "description": "This module deploys an API Management Service API.", @@ -1069,8 +1069,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2474188503939052987" + "version": "0.30.23.60470", + "templateHash": "5643177447182050438" }, "name": "API Management Service APIs Policies", "description": "This module deploys an API Management Service API Policy.", @@ -1216,8 +1216,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", @@ -1444,8 +1444,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17159723717884761443" + "version": "0.30.23.60470", + "templateHash": "2492486199367242598" }, "name": "API Management Service API Version Sets", "description": "This module deploys an API Management Service API Version Set.", @@ -1530,6 +1530,9 @@ "name": { "value": "[variables('authorizationServerList')[copyIndex()].name]" }, + "displayName": { + "value": "[variables('authorizationServerList')[copyIndex()].displayName]" + }, "authorizationEndpoint": { "value": "[variables('authorizationServerList')[copyIndex()].authorizationEndpoint]" }, @@ -1582,8 +1585,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4256977187793378377" + "version": "0.30.23.60470", + "templateHash": "17927787726774417819" }, "name": "API Management Service Authorization Servers", "description": "This module deploys an API Management Service Authorization Server.", @@ -1596,6 +1599,13 @@ "description": "Required. Identifier of the authorization server." } }, + "displayName": { + "type": "string", + "maxLength": 50, + "metadata": { + "description": "Required. API Management Service Authorization Servers name. Must be 1 to 50 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -1732,7 +1742,7 @@ "bearerTokenSendingMethods": "[parameters('bearerTokenSendingMethods')]", "resourceOwnerUsername": "[parameters('resourceOwnerUsername')]", "resourceOwnerPassword": "[parameters('resourceOwnerPassword')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "clientRegistrationEndpoint": "[parameters('clientRegistrationEndpoint')]", "authorizationEndpoint": "[parameters('authorizationEndpoint')]", "grantTypes": "[parameters('grantTypes')]", @@ -1825,8 +1835,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2365531440872951056" + "version": "0.30.23.60470", + "templateHash": "14706757128951530017" }, "name": "API Management Service Backends", "description": "This module deploys an API Management Service Backend.", @@ -2009,8 +2019,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3234729148013684780" + "version": "0.30.23.60470", + "templateHash": "2750555671183513052" }, "name": "API Management Service Caches", "description": "This module deploys an API Management Service Cache.", @@ -2167,8 +2177,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15630166564208731013" + "version": "0.30.23.60470", + "templateHash": "2531959928497745895" }, "name": "API Management Service APIs Diagnostics.", "description": "This module deploys an API Management Service API Diagnostics.", @@ -2397,8 +2407,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12757169124799431378" + "version": "0.30.23.60470", + "templateHash": "1342690797398622979" }, "name": "API Management Service Identity Providers", "description": "This module deploys an API Management Service Identity Provider.", @@ -2610,8 +2620,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12986610229102962453" + "version": "0.30.23.60470", + "templateHash": "12834599511984803283" }, "name": "API Management Service Loggers", "description": "This module deploys an API Management Service Logger.", @@ -2754,8 +2764,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3479776319506170502" + "version": "0.30.23.60470", + "templateHash": "10162843567606353040" }, "name": "API Management Service Named Values", "description": "This module deploys an API Management Service Named Value.", @@ -2895,8 +2905,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10271256088614129674" + "version": "0.30.23.60470", + "templateHash": "14869704072680236257" }, "name": "API Management Service Portal Settings", "description": "This module deploys an API Management Service Portal Setting.", @@ -2994,8 +3004,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11443463088593763324" + "version": "0.30.23.60470", + "templateHash": "9395795206748286282" }, "name": "API Management Service Policies", "description": "This module deploys an API Management Service Policy.", @@ -3089,6 +3099,9 @@ }, "mode": "Incremental", "parameters": { + "displayName": { + "value": "[parameters('products')[copyIndex()].displayName]" + }, "apiManagementServiceName": { "value": "[parameters('name')]" }, @@ -3126,8 +3139,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6230115773857876317" + "version": "0.30.23.60470", + "templateHash": "8029364311033748838" }, "name": "API Management Service Products", "description": "This module deploys an API Management Service Product.", @@ -3140,6 +3153,13 @@ "description": "Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment." } }, + "displayName": { + "type": "string", + "maxLength": 300, + "metadata": { + "description": "Required. API Management Service Products name. Must be 1 to 300 characters long." + } + }, "approvalRequired": { "type": "bool", "defaultValue": false, @@ -3210,7 +3230,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "description": "[parameters('description')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "terms": "[parameters('terms')]", "subscriptionRequired": "[parameters('subscriptionRequired')]", "approvalRequired": "[if(parameters('subscriptionRequired'), parameters('approvalRequired'), null())]", @@ -3248,8 +3268,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1052981479169082206" + "version": "0.30.23.60470", + "templateHash": "602104798329438871" }, "name": "API Management Service Products APIs", "description": "This module deploys an API Management Service Product API.", @@ -3338,8 +3358,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5748451278124986706" + "version": "0.30.23.60470", + "templateHash": "5238408376918932137" }, "name": "API Management Service Products Groups", "description": "This module deploys an API Management Service Product Group.", @@ -3469,6 +3489,9 @@ "name": { "value": "[parameters('subscriptions')[copyIndex()].name]" }, + "displayName": { + "value": "[parameters('subscriptions')[copyIndex()].displayName]" + }, "allowTracing": { "value": "[tryGet(parameters('subscriptions')[copyIndex()], 'allowTracing')]" }, @@ -3495,8 +3518,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9499976066778278010" + "version": "0.30.23.60470", + "templateHash": "16082435269276611452" }, "name": "API Management Service Subscriptions", "description": "This module deploys an API Management Service Subscription.", @@ -3510,6 +3533,13 @@ "description": "Optional. Determines whether tracing can be enabled." } }, + "displayName": { + "type": "string", + "maxLength": 100, + "metadata": { + "description": "Required. API Management Service Subscriptions name. Must be 1 to 100 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -3571,7 +3601,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "scope": "[parameters('scope')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "ownerId": "[parameters('ownerId')]", "primaryKey": "[parameters('primaryKey')]", "secondaryKey": "[parameters('secondaryKey')]", diff --git a/avm/res/api-management/service/named-value/main.json b/avm/res/api-management/service/named-value/main.json index 4be9cba518..b182535671 100644 --- a/avm/res/api-management/service/named-value/main.json +++ b/avm/res/api-management/service/named-value/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3479776319506170502" + "version": "0.30.23.60470", + "templateHash": "10162843567606353040" }, "name": "API Management Service Named Values", "description": "This module deploys an API Management Service Named Value.", diff --git a/avm/res/api-management/service/policy/main.json b/avm/res/api-management/service/policy/main.json index 83d9434240..dd3c7eab82 100644 --- a/avm/res/api-management/service/policy/main.json +++ b/avm/res/api-management/service/policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11443463088593763324" + "version": "0.30.23.60470", + "templateHash": "9395795206748286282" }, "name": "API Management Service Policies", "description": "This module deploys an API Management Service Policy.", diff --git a/avm/res/api-management/service/portalsetting/main.json b/avm/res/api-management/service/portalsetting/main.json index 779c574120..d68c8ed791 100644 --- a/avm/res/api-management/service/portalsetting/main.json +++ b/avm/res/api-management/service/portalsetting/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10271256088614129674" + "version": "0.30.23.60470", + "templateHash": "14869704072680236257" }, "name": "API Management Service Portal Settings", "description": "This module deploys an API Management Service Portal Setting.", diff --git a/avm/res/api-management/service/product/README.md b/avm/res/api-management/service/product/README.md index c5b8331a4a..9dbc604abb 100644 --- a/avm/res/api-management/service/product/README.md +++ b/avm/res/api-management/service/product/README.md @@ -22,6 +22,7 @@ This module deploys an API Management Service Product. | Parameter | Type | Description | | :-- | :-- | :-- | +| [`displayName`](#parameter-displayname) | string | API Management Service Products name. Must be 1 to 300 characters long. | | [`name`](#parameter-name) | string | Product Name. | **Conditional parameters** @@ -43,6 +44,13 @@ This module deploys an API Management Service Product. | [`subscriptionsLimit`](#parameter-subscriptionslimit) | int | Whether the number of subscriptions a user can have to this product at the same time. Set to null or omit to allow unlimited per user subscriptions. Can be present only if subscriptionRequired property is present and has a value of false. | | [`terms`](#parameter-terms) | string | Product terms of use. Developers trying to subscribe to the product will be presented and required to accept these terms before they can complete the subscription process. | +### Parameter: `displayName` + +API Management Service Products name. Must be 1 to 300 characters long. + +- Required: Yes +- Type: string + ### Parameter: `name` Product Name. diff --git a/avm/res/api-management/service/product/api/main.json b/avm/res/api-management/service/product/api/main.json index 4042b9bf61..5603f9f789 100644 --- a/avm/res/api-management/service/product/api/main.json +++ b/avm/res/api-management/service/product/api/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1052981479169082206" + "version": "0.30.23.60470", + "templateHash": "602104798329438871" }, "name": "API Management Service Products APIs", "description": "This module deploys an API Management Service Product API.", diff --git a/avm/res/api-management/service/product/group/main.json b/avm/res/api-management/service/product/group/main.json index 4ac13f0dac..28d5460152 100644 --- a/avm/res/api-management/service/product/group/main.json +++ b/avm/res/api-management/service/product/group/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5748451278124986706" + "version": "0.30.23.60470", + "templateHash": "5238408376918932137" }, "name": "API Management Service Products Groups", "description": "This module deploys an API Management Service Product Group.", diff --git a/avm/res/api-management/service/product/main.bicep b/avm/res/api-management/service/product/main.bicep index 9787974281..22ca0081c1 100644 --- a/avm/res/api-management/service/product/main.bicep +++ b/avm/res/api-management/service/product/main.bicep @@ -5,6 +5,10 @@ metadata owner = 'Azure/module-maintainers' @sys.description('Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment.') param apiManagementServiceName string +@sys.description('Required. API Management Service Products name. Must be 1 to 300 characters long.') +@maxLength(300) +param displayName string + @sys.description('Optional. Whether subscription approval is required. If false, new subscriptions will be approved automatically enabling developers to call the products APIs immediately after subscribing. If true, administrators must manually approve the subscription before the developer can any of the products APIs. Can be present only if subscriptionRequired property is present and has a value of false.') param approvalRequired bool = false @@ -41,7 +45,7 @@ resource product 'Microsoft.ApiManagement/service/products@2022-08-01' = { parent: service properties: { description: description - displayName: name + displayName: displayName terms: terms subscriptionRequired: subscriptionRequired approvalRequired: subscriptionRequired ? approvalRequired : null diff --git a/avm/res/api-management/service/product/main.json b/avm/res/api-management/service/product/main.json index 73dd3977b6..892a25de5c 100644 --- a/avm/res/api-management/service/product/main.json +++ b/avm/res/api-management/service/product/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6230115773857876317" + "version": "0.30.23.60470", + "templateHash": "8029364311033748838" }, "name": "API Management Service Products", "description": "This module deploys an API Management Service Product.", @@ -18,6 +18,13 @@ "description": "Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment." } }, + "displayName": { + "type": "string", + "maxLength": 300, + "metadata": { + "description": "Required. API Management Service Products name. Must be 1 to 300 characters long." + } + }, "approvalRequired": { "type": "bool", "defaultValue": false, @@ -88,7 +95,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "description": "[parameters('description')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "terms": "[parameters('terms')]", "subscriptionRequired": "[parameters('subscriptionRequired')]", "approvalRequired": "[if(parameters('subscriptionRequired'), parameters('approvalRequired'), null())]", @@ -126,8 +133,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1052981479169082206" + "version": "0.30.23.60470", + "templateHash": "602104798329438871" }, "name": "API Management Service Products APIs", "description": "This module deploys an API Management Service Product API.", @@ -216,8 +223,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5748451278124986706" + "version": "0.30.23.60470", + "templateHash": "5238408376918932137" }, "name": "API Management Service Products Groups", "description": "This module deploys an API Management Service Product Group.", diff --git a/avm/res/api-management/service/subscription/README.md b/avm/res/api-management/service/subscription/README.md index c851bed0dd..03e97821cd 100644 --- a/avm/res/api-management/service/subscription/README.md +++ b/avm/res/api-management/service/subscription/README.md @@ -20,6 +20,7 @@ This module deploys an API Management Service Subscription. | Parameter | Type | Description | | :-- | :-- | :-- | +| [`displayName`](#parameter-displayname) | string | API Management Service Subscriptions name. Must be 1 to 100 characters long. | | [`name`](#parameter-name) | string | Subscription name. | **Conditional parameters** @@ -39,6 +40,13 @@ This module deploys an API Management Service Subscription. | [`secondaryKey`](#parameter-secondarykey) | string | Secondary subscription key. If not specified during request key will be generated automatically. | | [`state`](#parameter-state) | string | Initial subscription state. If no value is specified, subscription is created with Submitted state. Possible states are "*" active "?" the subscription is active, "*" suspended "?" the subscription is blocked, and the subscriber cannot call any APIs of the product, * submitted ? the subscription request has been made by the developer, but has not yet been approved or rejected, * rejected ? the subscription request has been denied by an administrator, * cancelled ? the subscription has been cancelled by the developer or administrator, * expired ? the subscription reached its expiration date and was deactivated. - suspended, active, expired, submitted, rejected, cancelled. | +### Parameter: `displayName` + +API Management Service Subscriptions name. Must be 1 to 100 characters long. + +- Required: Yes +- Type: string + ### Parameter: `name` Subscription name. diff --git a/avm/res/api-management/service/subscription/main.bicep b/avm/res/api-management/service/subscription/main.bicep index 1b1e9411be..746242a7f9 100644 --- a/avm/res/api-management/service/subscription/main.bicep +++ b/avm/res/api-management/service/subscription/main.bicep @@ -5,6 +5,10 @@ metadata owner = 'Azure/module-maintainers' @description('Optional. Determines whether tracing can be enabled.') param allowTracing bool = true +@description('Required. API Management Service Subscriptions name. Must be 1 to 100 characters long.') +@maxLength(100) +param displayName string + @description('Conditional. The name of the parent API Management service. Required if the template is used in a standalone deployment.') param apiManagementServiceName string @@ -35,7 +39,7 @@ resource subscription 'Microsoft.ApiManagement/service/subscriptions@2022-08-01' parent: service properties: { scope: scope - displayName: name + displayName: displayName ownerId: ownerId primaryKey: primaryKey secondaryKey: secondaryKey diff --git a/avm/res/api-management/service/subscription/main.json b/avm/res/api-management/service/subscription/main.json index 5510d60858..6abc772cc3 100644 --- a/avm/res/api-management/service/subscription/main.json +++ b/avm/res/api-management/service/subscription/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9499976066778278010" + "version": "0.30.23.60470", + "templateHash": "16082435269276611452" }, "name": "API Management Service Subscriptions", "description": "This module deploys an API Management Service Subscription.", @@ -20,6 +20,13 @@ "description": "Optional. Determines whether tracing can be enabled." } }, + "displayName": { + "type": "string", + "maxLength": 100, + "metadata": { + "description": "Required. API Management Service Subscriptions name. Must be 1 to 100 characters long." + } + }, "apiManagementServiceName": { "type": "string", "metadata": { @@ -81,7 +88,7 @@ "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", "properties": { "scope": "[parameters('scope')]", - "displayName": "[parameters('name')]", + "displayName": "[parameters('displayName')]", "ownerId": "[parameters('ownerId')]", "primaryKey": "[parameters('primaryKey')]", "secondaryKey": "[parameters('secondaryKey')]", diff --git a/avm/res/api-management/service/tests/e2e/max/main.test.bicep b/avm/res/api-management/service/tests/e2e/max/main.test.bicep index 2989495645..e0419365c5 100644 --- a/avm/res/api-management/service/tests/e2e/max/main.test.bicep +++ b/avm/res/api-management/service/tests/e2e/max/main.test.bicep @@ -124,6 +124,7 @@ module testDeployment '../../../main.bicep' = [ 'authorizationCode' ] name: 'AuthServer1' + displayName: 'AuthServer1' tokenEndpoint: '${environment().authentication.loginEndpoint}651b43ce-ccb8-4301-b551-b04dd872d401/oauth2/v2.0/token' } ] @@ -241,6 +242,7 @@ module testDeployment '../../../main.bicep' = [ } ] name: 'Starter' + displayName: 'Starter' subscriptionRequired: false } ] @@ -270,6 +272,7 @@ module testDeployment '../../../main.bicep' = [ { name: 'testArmSubscriptionAllApis' scope: '/apis' + displayName: 'testArmSubscriptionAllApis' } ] managedIdentities: { diff --git a/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep index ccf1f295b4..b94ad37da7 100644 --- a/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep @@ -128,6 +128,7 @@ module testDeployment '../../../main.bicep' = [ 'authorizationCode' ] name: 'AuthServer1' + displayName: 'AuthServer1' tokenEndpoint: '${environment().authentication.loginEndpoint}651b43ce-ccb8-4301-b551-b04dd872d401/oauth2/v2.0/token' } ] @@ -243,6 +244,7 @@ module testDeployment '../../../main.bicep' = [ { name: 'testArmSubscriptionAllApis' scope: '/apis' + displayName: 'testArmSubscriptionAllApis' } ] tags: { diff --git a/avm/res/api-management/service/version.json b/avm/res/api-management/service/version.json index a8eda31021..9ed3662aba 100644 --- a/avm/res/api-management/service/version.json +++ b/avm/res/api-management/service/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.5", + "version": "0.6", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} diff --git a/avm/res/app-configuration/configuration-store/README.md b/avm/res/app-configuration/configuration-store/README.md index 06d8a2d62d..e7a84828bf 100644 --- a/avm/res/app-configuration/configuration-store/README.md +++ b/avm/res/app-configuration/configuration-store/README.md @@ -65,7 +65,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto
    -via JSON Parameter file +via JSON parameters file ```json { @@ -90,6 +90,23 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accmin001' +// Non-required parameters +param enablePurgeProtection = false +param location = '' +``` + +
    +

    + ### Example 2: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -144,7 +161,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    -via JSON Parameter file +via JSON parameters file ```json { @@ -208,6 +225,50 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accencr001' +// Non-required parameters +param createMode = 'Default' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param disableLocalAuth = '' +param enablePurgeProtection = false +param keyValues = [ + { + contentType: 'contentType' + name: 'keyName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + value: 'valueName' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param softDeleteRetentionInDays = 1 +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -319,7 +380,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    -via JSON Parameter file +via JSON parameters file ```json { @@ -448,6 +509,107 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accmax001' +// Non-required parameters +param createMode = 'Default' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = '' +param enablePurgeProtection = false +param keyValues = [ + { + contentType: 'contentType' + name: 'keyName' + roleAssignments: [ + { + name: '56e2c190-b31e-4518-84de-170b8a5c1b24' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + value: 'valueName' + } + { + name: 'keyName2' + value: 'valueName2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param replicaLocations = [ + 'centralus' + 'westus' +] +param roleAssignments = [ + { + name: '695044c2-3f1f-4843-970a-bed584b95a9a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param softDeleteRetentionInDays = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -504,7 +666,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    -via JSON Parameter file +via JSON parameters file ```json { @@ -564,6 +726,52 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accpe001' +// Non-required parameters +param createMode = 'Default' +param enablePurgeProtection = false +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param softDeleteRetentionInDays = 1 +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -618,7 +826,7 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    -via JSON Parameter file +via JSON parameters file ```json { @@ -684,6 +892,50 @@ module configurationStore 'br/public:avm/res/app-configuration/configuration-sto

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app-configuration/configuration-store:' + +// Required parameters +param name = 'accwaf001' +// Non-required parameters +param createMode = 'Default' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = '' +param enablePurgeProtection = false +param keyValues = [ + { + contentType: 'contentType' + name: 'keyName' + value: 'valueName' + } +] +param location = '' +param replicaLocations = [ + 'centralus' + 'westus' +] +param softDeleteRetentionInDays = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1303,6 +1555,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1435,6 +1698,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'App Compliance Automation Administrator'` + - `'App Compliance Automation Reader'` + - `'App Configuration Data Owner'` + - `'App Configuration Data Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app/container-app/README.md b/avm/res/app/container-app/README.md index 9ac975e122..b6c1bce086 100644 --- a/avm/res/app/container-app/README.md +++ b/avm/res/app/container-app/README.md @@ -69,7 +69,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -106,6 +106,33 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Without ingress enabled_ This instance deploys the module with ingress traffic completely disabled. @@ -144,7 +171,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -184,6 +211,34 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acapriv001' +// Non-required parameters +param disableIngress = true +param location = '' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -293,7 +348,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -412,6 +467,105 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + env: [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } + ] + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acamax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'e9bac1ee-aebe-4513-9337-49e87a7be05e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param secrets = { + secureList: [ + { + name: 'containerappstoredsecret' + value: '' + } + { + identity: '' + keyVaultUrl: '' + name: 'keyvaultstoredsecret' + } + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
    +

    + ### Example 4: _VNet integrated container app deployment_ This instance deploys the container app in a managed environment with a virtual network using TCP ingress. @@ -460,7 +614,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -518,6 +672,44 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acavnet001' +// Non-required parameters +param additionalPortMappings = [ + { + exposedPort: 8080 + external: false + targetPort: 8080 + } +] +param ingressAllowInsecure = false +param ingressExternal = false +param ingressTargetPort = 80 +param ingressTransport = 'tcp' +param location = '' +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -587,7 +779,7 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -666,6 +858,65 @@ module containerApp 'br/public:avm/res/app/container-app:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/container-app:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'acawaf001' +// Non-required parameters +param ingressAllowInsecure = false +param ingressExternal = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1409,6 +1660,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'ContainerApp Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app/job/README.md b/avm/res/app/job/README.md index a0d091b780..51e3119966 100644 --- a/avm/res/app/job/README.md +++ b/avm/res/app/job/README.md @@ -66,7 +66,7 @@ module job 'br/public:avm/res/app/job:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -105,6 +105,31 @@ module job 'br/public:avm/res/app/job:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + } +] +param environmentResourceId = '' +param name = 'ajcon001' +param triggerType = 'Manual' +// Non-required parameters +param location = '' +param manualTriggerConfig = {} +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -144,7 +169,7 @@ module job 'br/public:avm/res/app/job:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -187,6 +212,35 @@ module job 'br/public:avm/res/app/job:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + resources: { + cpu: '0.25' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'ajmin001' +param triggerType = 'Manual' +// Non-required parameters +param location = '' +param manualTriggerConfig = {} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -349,7 +403,7 @@ module job 'br/public:avm/res/app/job:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -529,6 +583,158 @@ module job 'br/public:avm/res/app/job:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + env: [ + { + name: 'AZURE_STORAGE_QUEUE_NAME' + value: '' + } + { + name: 'AZURE_STORAGE_CONNECTION_STRING' + secretRef: 'connection-string' + } + ] + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '1.25' + memory: '1.5Gi' + } + volumeMounts: [ + { + mountPath: '/mnt/data' + volumeName: 'ajmaxemptydir' + } + ] + } + { + args: [ + 'arg1' + 'arg2' + ] + command: [ + '-c' + '/bin/bash' + 'echo hello' + 'sleep 100000' + ] + env: [ + { + name: 'SOME_ENV_VAR' + value: 'some-value' + } + ] + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'second-simple-container' + } +] +param environmentResourceId = '' +param name = 'ajmax001' +param triggerType = 'Event' +// Non-required parameters +param eventTriggerConfig = { + parallelism: 1 + replicaCompletionCount: 1 + scale: { + maxExecutions: 1 + minExecutions: 1 + pollingInterval: 55 + rules: [ + { + auth: [ + { + secretRef: 'connectionString' + triggerParameter: 'connection' + } + ] + metadata: { + queueName: '' + storageAccountResourceId: '' + } + name: 'queue' + type: 'azure-queue' + } + ] + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'be1bb251-6a44-49f7-8658-d836d0049fc4' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param secrets = [ + { + name: 'connection-string' + value: '' + } +] +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param volumes = [ + { + name: 'ajmaxemptydir' + storageType: 'EmptyDir' + } +] +param workloadProfileName = '' +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -592,7 +798,7 @@ module job 'br/public:avm/res/app/job:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -663,6 +869,59 @@ module job 'br/public:avm/res/app/job:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/job:' + +// Required parameters +param containers = [ + { + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'simple-hello-world-container' + probes: [ + { + httpGet: { + httpHeaders: [ + { + name: 'Custom-Header' + value: 'Awesome' + } + ] + path: '/health' + port: 8080 + } + initialDelaySeconds: 3 + periodSeconds: 3 + type: 'Liveness' + } + ] + resources: { + cpu: '0.25' + memory: '0.5Gi' + } + } +] +param environmentResourceId = '' +param name = 'ajwaf001' +param triggerType = 'Schedule' +// Non-required parameters +param location = '' +param scheduleTriggerConfig = { + cronExpression: '0 0 * * *' +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param workloadProfileName = '' +``` + +
    +

    + ## Parameters **Required parameters** @@ -1741,6 +2000,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'ContainerApp Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/app/managed-environment/README.md b/avm/res/app/managed-environment/README.md index 66e8fe2364..3d5b5191c4 100644 --- a/avm/res/app/managed-environment/README.md +++ b/avm/res/app/managed-environment/README.md @@ -72,7 +72,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -125,6 +125,37 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/managed-environment:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'amemin001' +// Non-required parameters +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetId = '' +param internal = true +param location = '' +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -227,7 +258,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -357,6 +388,98 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/managed-environment:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'amemax001' +// Non-required parameters +param appInsightsConnectionString = '' +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetId = '' +param internal = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param openTelemetryConfiguration = { + logsConfiguration: { + destinations: [ + 'appInsights' + ] + } + tracesConfiguration: { + destinations: [ + 'appInsights' + ] + } +} +param peerTrafficEncryption = true +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param roleAssignments = [ + { + name: '43fc5250-f111-472b-8722-f1cb4a0e754b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storages = [ + { + accessMode: 'ReadWrite' + kind: 'SMB' + shareName: 'smbfileshare' + storageAccountName: '' + } + { + accessMode: 'ReadWrite' + kind: 'NFS' + shareName: 'nfsfileshare' + storageAccountName: '' + } +] +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -423,7 +546,7 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -507,6 +630,62 @@ module managedEnvironment 'br/public:avm/res/app/managed-environment:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/app/managed-environment:' + +// Required parameters +param logAnalyticsWorkspaceResourceId = '' +param name = 'amewaf001' +// Non-required parameters +param dockerBridgeCidr = '172.16.0.1/28' +param infrastructureResourceGroupName = '' +param infrastructureSubnetId = '' +param internal = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param platformReservedCidr = '172.17.17.0/24' +param platformReservedDnsIP = '172.17.17.17' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param workloadProfiles = [ + { + maximumCount: 3 + minimumCount: 0 + name: 'CAW01' + workloadProfileType: 'D4' + } +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -778,6 +957,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md index 8aa19e6b65..549a0c129e 100644 --- a/avm/res/automation/automation-account/README.md +++ b/avm/res/automation/automation-account/README.md @@ -70,7 +70,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,22 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using encryption with Customer-Managed-Key_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -128,7 +144,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -164,6 +180,32 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aaencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -422,7 +464,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -708,6 +750,254 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aamax001' +// Non-required parameters +param credentials = [ + { + description: 'Description of Credential01' + name: 'Credential01' + password: '' + userName: 'userName01' + } + { + name: 'Credential02' + password: '' + userName: 'username02' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param gallerySolutions = [ + { + name: 'Updates' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param jobSchedules = [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } +] +param linkedWorkspaceResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param modules = [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: 'de334944-f952-4273-8ab3-bd523380034c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param runbooks = [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } +] +param schedules = [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } +] +param softwareUpdateConfigurations = [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param variables = [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + isEncrypted: false + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } +] +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -917,7 +1207,7 @@ module automationAccount 'br/public:avm/res/automation/automation-account: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1150,6 +1440,205 @@ module automationAccount 'br/public:avm/res/automation/automation-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/automation/automation-account:' + +// Required parameters +param name = 'aawaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param gallerySolutions = [ + { + name: 'Updates' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param jobSchedules = [ + { + runbookName: 'TestRunbook' + scheduleName: 'TestSchedule' + } +] +param linkedWorkspaceResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param modules = [ + { + name: 'PSWindowsUpdate' + uri: 'https://www.powershellgallery.com/api/v2/package' + version: 'latest' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Webhook' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'DSCAndHybridWorker' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param runbooks = [ + { + description: 'Test runbook' + name: 'TestRunbook' + type: 'PowerShell' + uri: 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/quickstarts/microsoft.automation/101-automation/scripts/AzureAutomationTutorial.ps1' + version: '1.0.0.0' + } +] +param schedules = [ + { + advancedSchedule: {} + expiryTime: '9999-12-31T13:00' + frequency: 'Hour' + interval: 12 + name: 'TestSchedule' + startTime: '' + timeZone: 'Europe/Berlin' + } +] +param softwareUpdateConfigurations = [ + { + excludeUpdates: [ + '123456' + ] + frequency: 'Month' + includeUpdates: [ + '654321' + ] + interval: 1 + maintenanceWindow: 'PT4H' + monthlyOccurrences: [ + { + day: 'Friday' + occurrence: 3 + } + ] + name: 'Windows_ZeroDay' + operatingSystem: 'Windows' + rebootSetting: 'IfRequired' + scopeByTags: { + Update: [ + 'Automatic-Wave1' + ] + } + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Definition' + 'FeaturePack' + 'Security' + 'ServicePack' + 'Tools' + 'UpdateRollup' + 'Updates' + ] + } + { + excludeUpdates: [ + 'icacls' + ] + frequency: 'OneTime' + includeUpdates: [ + 'kernel' + ] + maintenanceWindow: 'PT4H' + name: 'Linux_ZeroDay' + operatingSystem: 'Linux' + rebootSetting: 'IfRequired' + startTime: '22:00' + updateClassifications: [ + 'Critical' + 'Other' + 'Security' + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param variables = [ + { + description: 'TestStringDescription' + name: 'TestString' + value: '\'TestString\'' + } + { + description: 'TestIntegerDescription' + name: 'TestInteger' + value: '500' + } + { + description: 'TestBooleanDescription' + name: 'TestBoolean' + value: 'false' + } + { + description: 'TestDateTimeDescription' + name: 'TestDateTime' + value: '\'\\/Date(1637934042656)\\/\'' + } + { + description: 'TestEncryptedDescription' + name: 'TestEncryptedVariable' + value: '\'TestEncryptedValue\'' + } +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -1853,6 +2342,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1973,6 +2473,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Automation Contributor'` + - `'Automation Job Operator'` + - `'Automation Operator'` + - `'Automation Runbook Operator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 7b725694d8..0cf0a66b37 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -62,7 +62,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,23 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbamin001' +param storageAccountId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -128,7 +145,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -177,6 +194,37 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbaencr001' +param storageAccountId = '' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param poolAllocationMode = 'BatchService' +param storageAuthenticationMode = 'BatchAccountManagedIdentity' +param tags = { + 'hidden-title': 'This is visible in the resource name' +} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -346,7 +394,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -533,6 +581,165 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbamax001' +param storageAccountId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param networkProfile = { + accountAccess: { + allowedIpRules: [ + '40.74.28.0/23' + ] + defaultAction: 'Deny' + } + nodeManagementAccess: { + allowedIpRules: [ + '40.74.28.0/23' + ] + } +} +param poolAllocationMode = 'BatchService' +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.batch.com' + ipAddresses: [ + '10.0.16.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'batchAccount' + memberName: 'batchAccount' + privateIPAddress: '10.0.16.10' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + name: '9afa4fb3-2157-40db-aebb-039ce73c50ca' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + service: 'batchAccount' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'batchAccount' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'nodeManagement' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: 'd57821b0-52b3-4a42-9799-533a9cdb7eec' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageAccessIdentityResourceId = '' +param storageAuthenticationMode = 'BatchAccountManagedIdentity' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -596,7 +803,7 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -673,6 +880,59 @@ module batchAccount 'br/public:avm/res/batch/batch-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/batch/batch-account:' + +// Required parameters +param name = 'bbawaf001' +param storageAccountId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param poolAllocationMode = 'BatchService' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'batchAccount' + subnetResourceId: '' + } +] +param storageAccessIdentityResourceId = '' +param storageAuthenticationMode = 'BatchAccountManagedIdentity' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1407,6 +1667,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1527,6 +1798,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/cache/redis/README.md b/avm/res/cache/redis/README.md index 53940a6aa5..de250d1472 100644 --- a/avm/res/cache/redis/README.md +++ b/avm/res/cache/redis/README.md @@ -64,7 +64,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module redis 'br/public:avm/res/cache/redis:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using EntraID authentication_ This instance deploys the module with EntraID authentication. @@ -115,7 +131,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -142,6 +158,25 @@ module redis 'br/public:avm/res/cache/redis:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crentrid001' +// Non-required parameters +param location = '' +param redisConfiguration = { + 'aad-enabled': 'true' +} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -271,7 +306,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -424,6 +459,125 @@ module redis 'br/public:avm/res/cache/redis:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crmax001' +// Non-required parameters +param capacity = 2 +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableNonSslPort = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param minimumTlsVersion = '1.2' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + name: '8d6043f5-8a22-447f-bc31-23d23e09de6c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param redisVersion = '6' +param roleAssignments = [ + { + name: 'f20e5c94-a697-421e-8768-d576399dbd87' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param shardCount = 1 +param skuName = 'Premium' +param tags = { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Redis Cache' +} +param zoneRedundant = true +param zones = [ + 1 + 2 +] +``` + +
    +

    + ### Example 4: _Passive Geo-Replicated Redis Cache_ This instance deploys the module with geo-replication enabled. @@ -468,7 +622,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -530,6 +684,40 @@ module redis 'br/public:avm/res/cache/redis:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crpgeo001' +// Non-required parameters +param capacity = 2 +param enableNonSslPort = true +param geoReplicationObject = { + linkedRedisCacheLocation: '' + linkedRedisCacheResourceId: '' + name: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param minimumTlsVersion = '1.2' +param redisVersion = '6' +param replicasPerMaster = 1 +param replicasPerPrimary = 1 +param shardCount = 1 +param skuName = 'Premium' +param zoneRedundant = false +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -612,7 +800,7 @@ module redis 'br/public:avm/res/cache/redis:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -720,6 +908,78 @@ module redis 'br/public:avm/res/cache/redis:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis:' + +// Required parameters +param name = 'crwaf001' +// Non-required parameters +param capacity = 2 +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableNonSslPort = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param minimumTlsVersion = '1.2' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param redisVersion = '6' +param replicasPerMaster = 3 +param replicasPerPrimary = 3 +param shardCount = 1 +param skuName = 'Premium' +param tags = { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Redis Cache' +} +param zoneRedundant = true +param zones = [ + 1 + 2 + 3 +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -734,6 +994,7 @@ module redis 'br/public:avm/res/cache/redis:' = { | :-- | :-- | :-- | | [`capacity`](#parameter-capacity) | int | The size of the Redis cache to deploy. Valid values: for C (Basic/Standard) family (0, 1, 2, 3, 4, 5, 6), for P (Premium) family (1, 2, 3, 4). | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disableAccessKeyAuthentication`](#parameter-disableaccesskeyauthentication) | bool | Disable authentication via access keys. | | [`enableNonSslPort`](#parameter-enablenonsslport) | bool | Specifies whether the non-ssl Redis server port (6379) is enabled. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`geoReplicationObject`](#parameter-georeplicationobject) | object | The geo-replication settings of the service. Requires a Premium SKU. Geo-replication is not supported on a cache with multiple replicas per primary. Secondary cache VM Size must be same or higher as compared to the primary cache VM Size. Geo-replication between a vnet and non vnet cache (and vice-a-versa) not supported. | @@ -930,6 +1191,14 @@ Resource ID of the diagnostic log analytics workspace. For security reasons, it - Required: No - Type: string +### Parameter: `disableAccessKeyAuthentication` + +Disable authentication via access keys. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `enableNonSslPort` Specifies whether the non-ssl Redis server port (6379) is enabled. @@ -1332,6 +1601,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1498,6 +1778,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Redis Cache Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/cache/redis/linked-servers/main.json b/avm/res/cache/redis/linked-servers/main.json index 67532e2795..1352156fef 100644 --- a/avm/res/cache/redis/linked-servers/main.json +++ b/avm/res/cache/redis/linked-servers/main.json @@ -98,4 +98,4 @@ "value": "[resourceGroup().name]" } } -} \ No newline at end of file +} diff --git a/avm/res/cache/redis/main.bicep b/avm/res/cache/redis/main.bicep index 09212df80b..9e866bb89e 100644 --- a/avm/res/cache/redis/main.bicep +++ b/avm/res/cache/redis/main.bicep @@ -20,6 +20,9 @@ param tags object? @description('Optional. The managed identity definition for this resource.') param managedIdentities managedIdentitiesType +@description('Optional. Disable authentication via access keys.') +param disableAccessKeyAuthentication bool = false + @description('Optional. Specifies whether the non-ssl Redis server port (6379) is enabled.') param enableNonSslPort bool = false @@ -181,6 +184,7 @@ resource redis 'Microsoft.Cache/redis@2024-03-01' = { tags: tags identity: identity properties: { + disableAccessKeyAuthentication: disableAccessKeyAuthentication enableNonSslPort: enableNonSslPort minimumTlsVersion: minimumTlsVersion publicNetworkAccess: !empty(publicNetworkAccess) diff --git a/avm/res/cache/redis/main.json b/avm/res/cache/redis/main.json index f9b3301dcb..222f86491e 100644 --- a/avm/res/cache/redis/main.json +++ b/avm/res/cache/redis/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "2147401251365362685" + "templateHash": "8427702382536251551" }, "name": "Redis Cache", "description": "This module deploys a Redis Cache.", @@ -514,6 +514,13 @@ "description": "Optional. The managed identity definition for this resource." } }, + "disableAccessKeyAuthentication": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable authentication via access keys." + } + }, "enableNonSslPort": { "type": "bool", "defaultValue": false, @@ -733,6 +740,7 @@ "tags": "[parameters('tags')]", "identity": "[variables('identity')]", "properties": { + "disableAccessKeyAuthentication": "[parameters('disableAccessKeyAuthentication')]", "enableNonSslPort": "[parameters('enableNonSslPort')]", "minimumTlsVersion": "[parameters('minimumTlsVersion')]", "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', null()))]", @@ -1801,4 +1809,4 @@ } } } -} \ No newline at end of file +} diff --git a/avm/res/cdn/profile/README.md b/avm/res/cdn/profile/README.md index ccaf732ba3..cdbbe70b4d 100644 --- a/avm/res/cdn/profile/README.md +++ b/avm/res/cdn/profile/README.md @@ -27,6 +27,7 @@ This module deploys a CDN Profile. | `Microsoft.Cdn/profiles/ruleSets` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2023-05-01/profiles/ruleSets) | | `Microsoft.Cdn/profiles/ruleSets/rules` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2023-05-01/profiles/ruleSets/rules) | | `Microsoft.Cdn/profiles/secrets` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/2023-05-01/profiles/secrets) | +| `Microsoft.Cdn/profiles/securityPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/profiles/securityPolicies) | ## Usage examples @@ -36,12 +37,346 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/cdn/profile:`. -- [As Azure Front Door](#example-1-as-azure-front-door) -- [Using only defaults](#example-2-using-only-defaults) -- [Using large parameter set](#example-3-using-large-parameter-set) -- [WAF-aligned](#example-4-waf-aligned) +- [As Azure Front Door Premium](#example-1-as-azure-front-door-premium) +- [As Azure Front Door](#example-2-as-azure-front-door) +- [Using only defaults](#example-3-using-only-defaults) +- [Using large parameter set](#example-4-using-large-parameter-set) +- [WAF-aligned](#example-5-waf-aligned) -### Example 1: _As Azure Front Door_ +### Example 1: _As Azure Front Door Premium_ + +This instance deploys the module as Azure Front Door Premium. + + +

    + +via Bicep module + +```bicep +module profile 'br/public:avm/res/cdn/profile:' = { + name: 'profileDeployment' + params: { + // Required parameters + name: 'dep-test-cdnpafdp' + sku: 'Premium_AzureFrontDoor' + // Non-required parameters + afdEndpoints: [ + { + name: 'dep-test-cdnpafdp-afd-endpoint' + routes: [ + { + customDomainNames: [ + 'dep-test-cdnpafdp-custom-domain' + ] + name: 'dep-test-cdnpafdp-afd-route' + originGroupName: 'dep-test-cdnpafdp-origin-group' + ruleSets: [ + { + name: 'deptestcdnpafdpruleset' + } + ] + } + ] + } + ] + customDomains: [ + { + certificateType: 'ManagedCertificate' + hostName: 'dep-test-cdnpafdp-custom-domain.azurewebsites.net' + name: 'dep-test-cdnpafdp-custom-domain' + } + ] + location: 'global' + originGroups: [ + { + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + name: 'dep-test-cdnpafdp-origin-group' + origins: [ + { + hostName: 'dep-test-cdnpafdp-origin.azurewebsites.net' + name: 'dep-test-cdnpafdp-origin' + } + ] + } + ] + originResponseTimeoutSeconds: 60 + ruleSets: [ + { + name: 'deptestcdnpafdpruleset' + rules: [ + { + actions: [ + { + name: 'UrlRedirect' + parameters: { + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + customPath: '/test123' + destinationProtocol: 'Https' + redirectType: 'PermanentRedirect' + typeName: 'DeliveryRuleUrlRedirectActionParameters' + } + } + ] + name: 'deptestcdnpafdprule' + order: 1 + } + ] + } + ] + securityPolicies: [ + { + associations: [ + { + domains: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + } + ] + name: 'deptestcdnpafdpsecpol' + wafPolicyResourceId: '' + } + ] + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "dep-test-cdnpafdp" + }, + "sku": { + "value": "Premium_AzureFrontDoor" + }, + // Non-required parameters + "afdEndpoints": { + "value": [ + { + "name": "dep-test-cdnpafdp-afd-endpoint", + "routes": [ + { + "customDomainNames": [ + "dep-test-cdnpafdp-custom-domain" + ], + "name": "dep-test-cdnpafdp-afd-route", + "originGroupName": "dep-test-cdnpafdp-origin-group", + "ruleSets": [ + { + "name": "deptestcdnpafdpruleset" + } + ] + } + ] + } + ] + }, + "customDomains": { + "value": [ + { + "certificateType": "ManagedCertificate", + "hostName": "dep-test-cdnpafdp-custom-domain.azurewebsites.net", + "name": "dep-test-cdnpafdp-custom-domain" + } + ] + }, + "location": { + "value": "global" + }, + "originGroups": { + "value": [ + { + "loadBalancingSettings": { + "additionalLatencyInMilliseconds": 50, + "sampleSize": 4, + "successfulSamplesRequired": 3 + }, + "name": "dep-test-cdnpafdp-origin-group", + "origins": [ + { + "hostName": "dep-test-cdnpafdp-origin.azurewebsites.net", + "name": "dep-test-cdnpafdp-origin" + } + ] + } + ] + }, + "originResponseTimeoutSeconds": { + "value": 60 + }, + "ruleSets": { + "value": [ + { + "name": "deptestcdnpafdpruleset", + "rules": [ + { + "actions": [ + { + "name": "UrlRedirect", + "parameters": { + "customHostname": "dev-etradefd.trade.azure.defra.cloud", + "customPath": "/test123", + "destinationProtocol": "Https", + "redirectType": "PermanentRedirect", + "typeName": "DeliveryRuleUrlRedirectActionParameters" + } + } + ], + "name": "deptestcdnpafdprule", + "order": 1 + } + ] + } + ] + }, + "securityPolicies": { + "value": [ + { + "associations": [ + { + "domains": [ + { + "id": "" + } + ], + "patternsToMatch": [ + "/*" + ] + } + ], + "name": "deptestcdnpafdpsecpol", + "wafPolicyResourceId": "" + } + ] + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpafdp' +param sku = 'Premium_AzureFrontDoor' +// Non-required parameters +param afdEndpoints = [ + { + name: 'dep-test-cdnpafdp-afd-endpoint' + routes: [ + { + customDomainNames: [ + 'dep-test-cdnpafdp-custom-domain' + ] + name: 'dep-test-cdnpafdp-afd-route' + originGroupName: 'dep-test-cdnpafdp-origin-group' + ruleSets: [ + { + name: 'deptestcdnpafdpruleset' + } + ] + } + ] + } +] +param customDomains = [ + { + certificateType: 'ManagedCertificate' + hostName: 'dep-test-cdnpafdp-custom-domain.azurewebsites.net' + name: 'dep-test-cdnpafdp-custom-domain' + } +] +param location = 'global' +param originGroups = [ + { + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + name: 'dep-test-cdnpafdp-origin-group' + origins: [ + { + hostName: 'dep-test-cdnpafdp-origin.azurewebsites.net' + name: 'dep-test-cdnpafdp-origin' + } + ] + } +] +param originResponseTimeoutSeconds = 60 +param ruleSets = [ + { + name: 'deptestcdnpafdpruleset' + rules: [ + { + actions: [ + { + name: 'UrlRedirect' + parameters: { + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + customPath: '/test123' + destinationProtocol: 'Https' + redirectType: 'PermanentRedirect' + typeName: 'DeliveryRuleUrlRedirectActionParameters' + } + } + ] + name: 'deptestcdnpafdprule' + order: 1 + } + ] + } +] +param securityPolicies = [ + { + associations: [ + { + domains: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + } + ] + name: 'deptestcdnpafdpsecpol' + wafPolicyResourceId: '' + } +] +``` + +
    +

    + +### Example 2: _As Azure Front Door_ This instance deploys the module as Azure Front Door. @@ -85,6 +420,9 @@ module profile 'br/public:avm/res/cdn/profile:' = { } ] location: 'global' + managedIdentities: { + systemAssigned: true + } originGroups: [ { loadBalancingSettings: { @@ -134,7 +472,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -182,6 +520,11 @@ module profile 'br/public:avm/res/cdn/profile:' = { "location": { "value": "global" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "originGroups": { "value": [ { @@ -235,7 +578,93 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -### Example 2: _Using only defaults_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpafd' +param sku = 'Standard_AzureFrontDoor' +// Non-required parameters +param afdEndpoints = [ + { + name: 'dep-test-cdnpafd-afd-endpoint' + routes: [ + { + customDomainNames: [ + 'dep-test-cdnpafd-custom-domain' + ] + name: 'dep-test-cdnpafd-afd-route' + originGroupName: 'dep-test-cdnpafd-origin-group' + ruleSets: [ + { + name: 'deptestcdnpafdruleset' + } + ] + } + ] + } +] +param customDomains = [ + { + certificateType: 'ManagedCertificate' + hostName: 'dep-test-cdnpafd-custom-domain.azurewebsites.net' + name: 'dep-test-cdnpafd-custom-domain' + } +] +param location = 'global' +param managedIdentities = { + systemAssigned: true +} +param originGroups = [ + { + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + name: 'dep-test-cdnpafd-origin-group' + origins: [ + { + hostName: 'dep-test-cdnpafd-origin.azurewebsites.net' + name: 'dep-test-cdnpafd-origin' + } + ] + } +] +param originResponseTimeoutSeconds = 60 +param ruleSets = [ + { + name: 'deptestcdnpafdruleset' + rules: [ + { + actions: [ + { + name: 'UrlRedirect' + parameters: { + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + customPath: '/test123' + destinationProtocol: 'Https' + redirectType: 'PermanentRedirect' + typeName: 'DeliveryRuleUrlRedirectActionParameters' + } + } + ] + name: 'deptestcdnpafdrule' + order: 1 + } + ] + } +] +``` + +
    +

    + +### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -262,7 +691,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -287,7 +716,24 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -### Example 3: _Using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpmin' +param sku = 'Standard_Microsoft' +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -368,7 +814,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -455,7 +901,78 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -### Example 4: _WAF-aligned_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpmax' +param sku = 'Standard_Verizon' +// Non-required parameters +param endpointProperties = { + contentTypesToCompress: [ + 'application/javascript' + 'application/json' + 'application/x-javascript' + 'application/xml' + 'text/css' + 'text/html' + 'text/javascript' + 'text/plain' + ] + geoFilters: [] + isCompressionEnabled: true + isHttpAllowed: true + isHttpsAllowed: true + originGroups: [] + originHostHeader: '' + origins: [ + { + name: 'dep-cdn-endpoint01' + properties: { + enabled: true + hostName: '' + httpPort: 80 + httpsPort: 443 + } + } + ] + queryStringCachingBehavior: 'IgnoreQueryString' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param originResponseTimeoutSeconds = 60 +param roleAssignments = [ + { + name: '50362c78-6910-43c3-8639-9cae123943bb' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
    +

    + +### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -513,7 +1030,7 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -573,6 +1090,54 @@ module profile 'br/public:avm/res/cdn/profile:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cdn/profile:' + +// Required parameters +param name = 'dep-test-cdnpwaf' +param sku = 'Standard_Verizon' +// Non-required parameters +param endpointProperties = { + contentTypesToCompress: [ + 'application/javascript' + 'application/json' + 'application/x-javascript' + 'application/xml' + 'text/css' + 'text/html' + 'text/javascript' + 'text/plain' + ] + geoFilters: [] + isCompressionEnabled: true + isHttpAllowed: true + isHttpsAllowed: true + originGroups: [] + originHostHeader: '' + origins: [ + { + name: 'dep-cdn-endpoint01' + properties: { + enabled: true + hostName: '' + httpPort: 80 + httpsPort: 443 + } + } + ] + queryStringCachingBehavior: 'IgnoreQueryString' +} +param location = '' +param originResponseTimeoutSeconds = 60 +``` + +
    +

    + ## Parameters **Required parameters** @@ -599,10 +1164,12 @@ module profile 'br/public:avm/res/cdn/profile:' = { | [`endpointProperties`](#parameter-endpointproperties) | object | Endpoint properties (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/endpoints?pivots=deployment-language-bicep#endpointproperties for details). | | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`originResponseTimeoutSeconds`](#parameter-originresponsetimeoutseconds) | int | Send and receive timeout on forwarding request to the origin. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`ruleSets`](#parameter-rulesets) | array | Array of rule set objects. | | [`secrets`](#parameter-secrets) | array | Array of secret objects. | +| [`securityPolicies`](#parameter-securitypolicies) | array | Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details). | | [`tags`](#parameter-tags) | object | Endpoint tags. | ### Parameter: `name` @@ -726,6 +1293,34 @@ Specify the name of lock. - Required: No - Type: string +### Parameter: `managedIdentities` + +The managed identity definition for this resource. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + ### Parameter: `originResponseTimeoutSeconds` Send and receive timeout on forwarding request to the origin. @@ -740,6 +1335,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'CDN Endpoint Contributor'` + - `'CDN Endpoint Reader'` + - `'CDN Profile Contributor'` + - `'CDN Profile Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -847,6 +1452,77 @@ Array of secret objects. - Type: array - Default: `[]` +### Parameter: `securityPolicies` + +Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details). + +- Required: No +- Type: array +- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associations`](#parameter-securitypoliciesassociations) | array | Domain names and URL patterns to math with this association. | +| [`name`](#parameter-securitypoliciesname) | string | Name of the security policy. | +| [`wafPolicyResourceId`](#parameter-securitypolicieswafpolicyresourceid) | string | Resource ID of WAF policy. | + +### Parameter: `securityPolicies.associations` + +Domain names and URL patterns to math with this association. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domains`](#parameter-securitypoliciesassociationsdomains) | array | List of domain resource id to associate with this resource. | +| [`patternsToMatch`](#parameter-securitypoliciesassociationspatternstomatch) | array | List of patterns to match with this association. | + +### Parameter: `securityPolicies.associations.domains` + +List of domain resource id to associate with this resource. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-securitypoliciesassociationsdomainsid) | string | ResourceID to domain that will be associated. | + +### Parameter: `securityPolicies.associations.domains.id` + +ResourceID to domain that will be associated. + +- Required: Yes +- Type: string + +### Parameter: `securityPolicies.associations.patternsToMatch` + +List of patterns to match with this association. + +- Required: Yes +- Type: array + +### Parameter: `securityPolicies.name` + +Name of the security policy. + +- Required: Yes +- Type: string + +### Parameter: `securityPolicies.wafPolicyResourceId` + +Resource ID of WAF policy. + +- Required: Yes +- Type: string + ### Parameter: `tags` Endpoint tags. @@ -865,6 +1541,7 @@ Endpoint tags. | `profileType` | string | The type of the CDN profile. | | `resourceGroupName` | string | The resource group where the CDN profile is deployed. | | `resourceId` | string | The resource ID of the CDN profile. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | | `uri` | string | The uri of the CDN profile endpoint. | ## Data Collection diff --git a/avm/res/cdn/profile/afdEndpoint/main.json b/avm/res/cdn/profile/afdEndpoint/main.json index 1f55d5cd6e..7cfef24e3f 100644 --- a/avm/res/cdn/profile/afdEndpoint/main.json +++ b/avm/res/cdn/profile/afdEndpoint/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3384292547879688658" + "version": "0.30.23.60470", + "templateHash": "792735746278824384" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -156,8 +156,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18002678880456924020" + "version": "0.30.23.60470", + "templateHash": "1034122698174669197" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", diff --git a/avm/res/cdn/profile/afdEndpoint/route/main.json b/avm/res/cdn/profile/afdEndpoint/route/main.json index 6a415af662..852e97f10c 100644 --- a/avm/res/cdn/profile/afdEndpoint/route/main.json +++ b/avm/res/cdn/profile/afdEndpoint/route/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18002678880456924020" + "version": "0.30.23.60470", + "templateHash": "1034122698174669197" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", diff --git a/avm/res/cdn/profile/customdomain/main.json b/avm/res/cdn/profile/customdomain/main.json index dd0a43d181..e45727e4ad 100644 --- a/avm/res/cdn/profile/customdomain/main.json +++ b/avm/res/cdn/profile/customdomain/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15211066835326278081" + "version": "0.30.23.60470", + "templateHash": "16955838730426729961" }, "name": "CDN Profiles Custom Domains", "description": "This module deploys a CDN Profile Custom Domains.", diff --git a/avm/res/cdn/profile/endpoint/main.json b/avm/res/cdn/profile/endpoint/main.json index 2fa89e8711..273dbe9fce 100644 --- a/avm/res/cdn/profile/endpoint/main.json +++ b/avm/res/cdn/profile/endpoint/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6371656015674390162" + "version": "0.30.23.60470", + "templateHash": "3460565146034921053" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -125,8 +125,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11976988406992266750" + "version": "0.30.23.60470", + "templateHash": "4151069688274070352" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", diff --git a/avm/res/cdn/profile/endpoint/origin/main.json b/avm/res/cdn/profile/endpoint/origin/main.json index 13a2f8b35d..f4c079ff44 100644 --- a/avm/res/cdn/profile/endpoint/origin/main.json +++ b/avm/res/cdn/profile/endpoint/origin/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11976988406992266750" + "version": "0.30.23.60470", + "templateHash": "4151069688274070352" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", diff --git a/avm/res/cdn/profile/main.bicep b/avm/res/cdn/profile/main.bicep index c573133232..2c30c0c2e2 100644 --- a/avm/res/cdn/profile/main.bicep +++ b/avm/res/cdn/profile/main.bicep @@ -49,9 +49,15 @@ param ruleSets array = [] @description('Optional. Array of AFD endpoint objects.') param afdEndpoints array = [] +@description('Optional. Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details).') +param securityPolicies securityPolicyType = [] + @description('Optional. Endpoint tags.') param tags object? +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentitiesType + @description('Optional. The lock settings of the service.') param lock lockType @@ -102,6 +108,21 @@ var formattedRoleAssignments = [ }) ] +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + #disable-next-line no-deployments-resources resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { name: '46d3xbcp.res.cdn-profile.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' @@ -124,6 +145,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT resource profile 'Microsoft.Cdn/profiles@2023-05-01' = { name: name location: location + identity: identity sku: { name: sku } @@ -251,6 +273,22 @@ module profile_afdEndpoints 'afdEndpoint/main.bicep' = [ } ] +module profile_securityPolicies 'securityPolicies/main.bicep' = [ + for (securityPolicy, index) in securityPolicies: { + name: '${uniqueString(deployment().name)}-Profile-SecurityPolicy-${index}' + dependsOn: [ + profile_afdEndpoints + profile_customDomains + ] + params: { + name: securityPolicy.name + profileName: profile.name + associations: securityPolicy.associations + wafPolicyResourceId: securityPolicy.wafPolicyResourceId + } + } +] + @description('The name of the CDN profile.') output name string = profile.name @@ -275,10 +313,33 @@ output endpointId string = !empty(endpointProperties) ? profile_endpoint.outputs @description('The uri of the CDN profile endpoint.') output uri string = !empty(endpointProperties) ? profile_endpoint.outputs.uri : '' +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string = profile.?identity.?principalId ?? '' + // =============== // // Definitions // // =============== // +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? + +import { associationsType } from 'securityPolicies/main.bicep' +type securityPolicyType = { + @description('Required. Name of the security policy.') + name: string + + @description('Required. Domain names and URL patterns to math with this association.') + associations: associationsType + + @description('Required. Resource ID of WAF policy.') + wafPolicyResourceId: string +}[] + type lockType = { @description('Optional. Specify the name of lock.') name: string? diff --git a/avm/res/cdn/profile/main.json b/avm/res/cdn/profile/main.json index 965bf9cb4c..479e17ece5 100644 --- a/avm/res/cdn/profile/main.json +++ b/avm/res/cdn/profile/main.json @@ -5,14 +5,63 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16789354290120442948" + "version": "0.30.23.60470", + "templateHash": "14447016685732236984" }, "name": "CDN Profiles", "description": "This module deploys a CDN Profile.", "owner": "Azure/module-maintainers" }, "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "securityPolicyType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the security policy." + } + }, + "associations": { + "$ref": "#/definitions/associationsType", + "metadata": { + "description": "Required. Domain names and URL patterns to math with this association." + } + }, + "wafPolicyResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of WAF policy." + } + } + } + } + }, "lockType": { "type": "object", "properties": { @@ -110,6 +159,45 @@ } }, "nullable": true + }, + "associationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. ResourceID to domain that will be associated." + } + } + } + }, + "metadata": { + "description": "Required. List of domain resource id to associate with this resource." + } + }, + "patternsToMatch": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of patterns to match with this association." + } + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "securityPolicies/main.bicep" + } + } } }, "parameters": { @@ -202,6 +290,13 @@ "description": "Optional. Array of AFD endpoint objects." } }, + "securityPolicies": { + "$ref": "#/definitions/securityPolicyType", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Security Policy objects (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies for details)." + } + }, "tags": { "type": "object", "nullable": true, @@ -209,6 +304,12 @@ "description": "Optional. Endpoint tags." } }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, "lock": { "$ref": "#/definitions/lockType", "metadata": { @@ -247,7 +348,9 @@ "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + }, + "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(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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" }, "resources": { "avmTelemetry": { @@ -275,6 +378,7 @@ "apiVersion": "2023-05-01", "name": "[parameters('name')]", "location": "[parameters('location')]", + "identity": "[variables('identity')]", "sku": { "name": "[parameters('sku')]" }, @@ -350,8 +454,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6371656015674390162" + "version": "0.30.23.60470", + "templateHash": "3460565146034921053" }, "name": "CDN Profiles Endpoints", "description": "This module deploys a CDN Profile Endpoint.", @@ -470,8 +574,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11976988406992266750" + "version": "0.30.23.60470", + "templateHash": "4151069688274070352" }, "name": "CDN Profiles Endpoints Origins", "description": "This module deploys a CDN Profile Endpoint Origin.", @@ -723,8 +827,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "533126228291817357" + "version": "0.30.23.60470", + "templateHash": "7661706938502506866" }, "name": "CDN Profiles Secret", "description": "This module deploys a CDN Profile Secret.", @@ -872,8 +976,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15211066835326278081" + "version": "0.30.23.60470", + "templateHash": "16955838730426729961" }, "name": "CDN Profiles Custom Domains", "description": "This module deploys a CDN Profile Custom Domains.", @@ -1039,8 +1143,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1182415535491789973" + "version": "0.30.23.60470", + "templateHash": "16948516107556143812" }, "name": "CDN Profiles Origin Group", "description": "This module deploys a CDN Profile Origin Group.", @@ -1176,8 +1280,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14493731512795008787" + "version": "0.30.23.60470", + "templateHash": "4669077701065465911" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", @@ -1402,8 +1506,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9792708426765797662" + "version": "0.30.23.60470", + "templateHash": "11520922481694023973" }, "name": "CDN Profiles Rule Sets", "description": "This module deploys a CDN Profile rule set.", @@ -1488,8 +1592,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12904222825428666192" + "version": "0.30.23.60470", + "templateHash": "8818585542646204223" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", @@ -1676,8 +1780,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3384292547879688658" + "version": "0.30.23.60470", + "templateHash": "792735746278824384" }, "name": "CDN Profiles AFD Endpoints", "description": "This module deploys a CDN Profile AFD Endpoint.", @@ -1827,8 +1931,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18002678880456924020" + "version": "0.30.23.60470", + "templateHash": "1034122698174669197" }, "name": "CDN Profiles AFD Endpoint Route", "description": "This module deploys a CDN Profile AFD Endpoint route.", @@ -2119,6 +2223,168 @@ "profile_originGroups", "profile_ruleSets" ] + }, + "profile_securityPolicies": { + "copy": { + "name": "profile_securityPolicies", + "count": "[length(parameters('securityPolicies'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Profile-SecurityPolicy-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityPolicies')[copyIndex()].name]" + }, + "profileName": { + "value": "[parameters('name')]" + }, + "associations": { + "value": "[parameters('securityPolicies')[copyIndex()].associations]" + }, + "wafPolicyResourceId": { + "value": "[parameters('securityPolicies')[copyIndex()].wafPolicyResourceId]" + } + }, + "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.30.23.60470", + "templateHash": "11561080659040848436" + }, + "name": "CDN Profiles Security Policy", + "description": "This module deploys a CDN Profile Security Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "associationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. ResourceID to domain that will be associated." + } + } + } + }, + "metadata": { + "description": "Required. List of domain resource id to associate with this resource." + } + }, + "patternsToMatch": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of patterns to match with this association." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource name." + } + }, + "profileName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent CDN profile. Required if the template is used in a standalone deployment." + } + }, + "wafPolicyResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of WAF Policy." + } + }, + "associations": { + "$ref": "#/definitions/associationsType", + "metadata": { + "description": "Required. Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details)." + } + } + }, + "resources": { + "profile": { + "existing": true, + "type": "Microsoft.Cdn/profiles", + "apiVersion": "2023-05-01", + "name": "[parameters('profileName')]" + }, + "securityPolicies": { + "type": "Microsoft.Cdn/profiles/securityPolicies", + "apiVersion": "2024-02-01", + "name": "[format('{0}/{1}', parameters('profileName'), parameters('name'))]", + "properties": { + "parameters": { + "type": "WebApplicationFirewall", + "wafPolicy": { + "id": "[parameters('wafPolicyResourceId')]" + }, + "associations": "[parameters('associations')]" + } + }, + "dependsOn": [ + "profile" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secrect." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secrect." + }, + "value": "[resourceId('Microsoft.Cdn/profiles/securityPolicies', parameters('profileName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "profile", + "profile_afdEndpoints", + "profile_customDomains" + ] } }, "outputs": { @@ -2177,6 +2443,13 @@ "description": "The uri of the CDN profile endpoint." }, "value": "[if(not(empty(parameters('endpointProperties'))), reference('profile_endpoint').outputs.uri.value, '')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('profile', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" } } } \ No newline at end of file diff --git a/avm/res/cdn/profile/origingroup/main.json b/avm/res/cdn/profile/origingroup/main.json index 9a388bc48e..af9a692a27 100644 --- a/avm/res/cdn/profile/origingroup/main.json +++ b/avm/res/cdn/profile/origingroup/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1182415535491789973" + "version": "0.30.23.60470", + "templateHash": "16948516107556143812" }, "name": "CDN Profiles Origin Group", "description": "This module deploys a CDN Profile Origin Group.", @@ -142,8 +142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14493731512795008787" + "version": "0.30.23.60470", + "templateHash": "4669077701065465911" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", diff --git a/avm/res/cdn/profile/origingroup/origin/main.json b/avm/res/cdn/profile/origingroup/origin/main.json index 56306ce135..8ee5bf04df 100644 --- a/avm/res/cdn/profile/origingroup/origin/main.json +++ b/avm/res/cdn/profile/origingroup/origin/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14493731512795008787" + "version": "0.30.23.60470", + "templateHash": "4669077701065465911" }, "name": "CDN Profiles Origin", "description": "This module deploys a CDN Profile Origin.", diff --git a/avm/res/cdn/profile/ruleset/main.json b/avm/res/cdn/profile/ruleset/main.json index 47ff335b1c..2d040690b5 100644 --- a/avm/res/cdn/profile/ruleset/main.json +++ b/avm/res/cdn/profile/ruleset/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9792708426765797662" + "version": "0.30.23.60470", + "templateHash": "11520922481694023973" }, "name": "CDN Profiles Rule Sets", "description": "This module deploys a CDN Profile rule set.", @@ -91,8 +91,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12904222825428666192" + "version": "0.30.23.60470", + "templateHash": "8818585542646204223" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", diff --git a/avm/res/cdn/profile/ruleset/rule/main.json b/avm/res/cdn/profile/ruleset/rule/main.json index bb37297681..98e0f0fef8 100644 --- a/avm/res/cdn/profile/ruleset/rule/main.json +++ b/avm/res/cdn/profile/ruleset/rule/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "12904222825428666192" + "version": "0.30.23.60470", + "templateHash": "8818585542646204223" }, "name": "CDN Profiles Rules", "description": "This module deploys a CDN Profile rule.", diff --git a/avm/res/cdn/profile/secret/main.json b/avm/res/cdn/profile/secret/main.json index a23afb02a0..6c300587db 100644 --- a/avm/res/cdn/profile/secret/main.json +++ b/avm/res/cdn/profile/secret/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "533126228291817357" + "version": "0.30.23.60470", + "templateHash": "7661706938502506866" }, "name": "CDN Profiles Secret", "description": "This module deploys a CDN Profile Secret.", diff --git a/avm/res/cdn/profile/securityPolicies/README.md b/avm/res/cdn/profile/securityPolicies/README.md new file mode 100644 index 0000000000..c30d3c5dad --- /dev/null +++ b/avm/res/cdn/profile/securityPolicies/README.md @@ -0,0 +1,101 @@ +# CDN Profiles Security Policy `[Microsoft.Cdn/profiles/securityPolicies]` + +This module deploys a CDN Profile Security Policy. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Cdn/profiles/securityPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cdn/profiles/securityPolicies) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associations`](#parameter-associations) | array | Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details). | +| [`name`](#parameter-name) | string | The resource name. | +| [`wafPolicyResourceId`](#parameter-wafpolicyresourceid) | string | Resource ID of WAF Policy. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`profileName`](#parameter-profilename) | string | The name of the parent CDN profile. Required if the template is used in a standalone deployment. | + +### Parameter: `associations` + +Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details). + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`domains`](#parameter-associationsdomains) | array | List of domain resource id to associate with this resource. | +| [`patternsToMatch`](#parameter-associationspatternstomatch) | array | List of patterns to match with this association. | + +### Parameter: `associations.domains` + +List of domain resource id to associate with this resource. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-associationsdomainsid) | string | ResourceID to domain that will be associated. | + +### Parameter: `associations.domains.id` + +ResourceID to domain that will be associated. + +- Required: Yes +- Type: string + +### Parameter: `associations.patternsToMatch` + +List of patterns to match with this association. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The resource name. + +- Required: Yes +- Type: string + +### Parameter: `wafPolicyResourceId` + +Resource ID of WAF Policy. + +- Required: Yes +- Type: string + +### Parameter: `profileName` + +The name of the parent CDN profile. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the secrect. | +| `resourceGroupName` | string | The name of the resource group the secret was created in. | +| `resourceId` | string | The resource ID of the secrect. | diff --git a/avm/res/cdn/profile/securityPolicies/main.bicep b/avm/res/cdn/profile/securityPolicies/main.bicep new file mode 100644 index 0000000000..1d98e235d9 --- /dev/null +++ b/avm/res/cdn/profile/securityPolicies/main.bicep @@ -0,0 +1,54 @@ +metadata name = 'CDN Profiles Security Policy' +metadata description = 'This module deploys a CDN Profile Security Policy.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The resource name.') +param name string + +@description('Conditional. The name of the parent CDN profile. Required if the template is used in a standalone deployment.') +param profileName string + +@description('Required. Resource ID of WAF Policy.') +param wafPolicyResourceId string + +// param associations associationsType +@description('Required. Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details).') +param associations associationsType + +resource profile 'Microsoft.Cdn/profiles@2023-05-01' existing = { + name: profileName +} + +resource securityPolicies 'Microsoft.Cdn/profiles/securityPolicies@2024-02-01' = { + name: name + parent: profile + properties: { + parameters: { + type: 'WebApplicationFirewall' + wafPolicy: { + id: wafPolicyResourceId + } + associations: associations + } + } +} + +@export() +type associationsType = { + @description('Required. List of domain resource id to associate with this resource.') + domains: { + @description('Required. ResourceID to domain that will be associated.') + id: string + }[] + @description('Required. List of patterns to match with this association.') + patternsToMatch: string[] +}[] + +@description('The name of the secrect.') +output name string = securityPolicies.name + +@description('The resource ID of the secrect.') +output resourceId string = securityPolicies.id + +@description('The name of the resource group the secret was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/cdn/profile/securityPolicies/main.json b/avm/res/cdn/profile/securityPolicies/main.json new file mode 100644 index 0000000000..be06e14c99 --- /dev/null +++ b/avm/res/cdn/profile/securityPolicies/main.json @@ -0,0 +1,128 @@ +{ + "$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.30.23.60470", + "templateHash": "11561080659040848436" + }, + "name": "CDN Profiles Security Policy", + "description": "This module deploys a CDN Profile Security Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "associationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. ResourceID to domain that will be associated." + } + } + } + }, + "metadata": { + "description": "Required. List of domain resource id to associate with this resource." + } + }, + "patternsToMatch": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of patterns to match with this association." + } + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource name." + } + }, + "profileName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent CDN profile. Required if the template is used in a standalone deployment." + } + }, + "wafPolicyResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of WAF Policy." + } + }, + "associations": { + "$ref": "#/definitions/associationsType", + "metadata": { + "description": "Required. Waf associations (see https://learn.microsoft.com/en-us/azure/templates/microsoft.cdn/profiles/securitypolicies?pivots=deployment-language-bicep#securitypolicywebapplicationfirewallassociation for details)." + } + } + }, + "resources": { + "profile": { + "existing": true, + "type": "Microsoft.Cdn/profiles", + "apiVersion": "2023-05-01", + "name": "[parameters('profileName')]" + }, + "securityPolicies": { + "type": "Microsoft.Cdn/profiles/securityPolicies", + "apiVersion": "2024-02-01", + "name": "[format('{0}/{1}', parameters('profileName'), parameters('name'))]", + "properties": { + "parameters": { + "type": "WebApplicationFirewall", + "wafPolicy": { + "id": "[parameters('wafPolicyResourceId')]" + }, + "associations": "[parameters('associations')]" + } + }, + "dependsOn": [ + "profile" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secrect." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secrect." + }, + "value": "[resourceId('Microsoft.Cdn/profiles/securityPolicies', parameters('profileName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep new file mode 100644 index 0000000000..e735b9c94b --- /dev/null +++ b/avm/res/cdn/profile/tests/e2e/afd.premium/main.test.bicep @@ -0,0 +1,146 @@ +targetScope = 'subscription' + +metadata name = 'As Azure Front Door Premium' +metadata description = 'This instance deploys the module as Azure Front Door Premium.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cdn.profiles-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'cdnpafdp' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module wafPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:0.2.0' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-dep-waf-policy-${serviceShort}' + params: { + name: 'dep${namePrefix}${serviceShort}wafpolicy' + sku: 'Premium_AzureFrontDoor' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'dep-${namePrefix}-test-${serviceShort}' + location: 'global' + originResponseTimeoutSeconds: 60 + sku: 'Premium_AzureFrontDoor' + customDomains: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-custom-domain' + hostName: 'dep-${namePrefix}-test-${serviceShort}-custom-domain.azurewebsites.net' + certificateType: 'ManagedCertificate' + } + ] + originGroups: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-origin-group' + loadBalancingSettings: { + additionalLatencyInMilliseconds: 50 + sampleSize: 4 + successfulSamplesRequired: 3 + } + origins: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-origin' + hostName: 'dep-${namePrefix}-test-${serviceShort}-origin.azurewebsites.net' + } + ] + } + ] + ruleSets: [ + { + name: 'dep${namePrefix}test${serviceShort}ruleset' + rules: [ + { + name: 'dep${namePrefix}test${serviceShort}rule' + order: 1 + actions: [ + { + name: 'UrlRedirect' + parameters: { + typeName: 'DeliveryRuleUrlRedirectActionParameters' + redirectType: 'PermanentRedirect' + destinationProtocol: 'Https' + customPath: '/test123' + customHostname: 'dev-etradefd.trade.azure.defra.cloud' + } + } + ] + } + ] + } + ] + afdEndpoints: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint' + routes: [ + { + name: 'dep-${namePrefix}-test-${serviceShort}-afd-route' + originGroupName: 'dep-${namePrefix}-test-${serviceShort}-origin-group' + customDomainNames: ['dep-${namePrefix}-test-${serviceShort}-custom-domain'] + ruleSets: [ + { + name: 'dep${namePrefix}test${serviceShort}ruleset' + } + ] + } + ] + } + ] + securityPolicies: [ + { + name: 'dep${namePrefix}test${serviceShort}secpol' + associations: [ + { + domains: [ + { + id: resourceId( + subscription().subscriptionId, + resourceGroup.name, + 'Microsoft.Cdn/profiles/afdEndpoints', + 'dep-${namePrefix}-test-${serviceShort}', + 'dep-${namePrefix}-test-${serviceShort}-afd-endpoint' + ) + } + ] + patternsToMatch: [ + '/*' + ] + } + ] + wafPolicyResourceId: wafPolicy.outputs.resourceId + } + ] + } + } +] diff --git a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep index 7fe9142055..66c9abbdfb 100644 --- a/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep +++ b/avm/res/cdn/profile/tests/e2e/afd/main.test.bicep @@ -42,6 +42,9 @@ module testDeployment '../../../main.bicep' = [ name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { name: 'dep-${namePrefix}-test-${serviceShort}' + managedIdentities: { + systemAssigned: true + } location: 'global' originResponseTimeoutSeconds: 60 sku: 'Standard_AzureFrontDoor' diff --git a/avm/res/cdn/profile/version.json b/avm/res/cdn/profile/version.json index a8eda31021..35040975ae 100644 --- a/avm/res/cdn/profile/version.json +++ b/avm/res/cdn/profile/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.5", + "version": "0.7", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 9838b6a3e6..fb852b55a3 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -20,6 +20,7 @@ This module deploys a Cognitive Service. | `Microsoft.CognitiveServices/accounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts) | | `Microsoft.CognitiveServices/accounts/deployments` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.CognitiveServices/2023-05-01/accounts/deployments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | @@ -33,13 +34,14 @@ The following section provides usage examples for the module, which were used to - [Using `AIServices` with `deployments` in parameter set and private endpoints](#example-1-using-aiservices-with-deployments-in-parameter-set-and-private-endpoints) - [Using `AIServices` with `deployments` in parameter set](#example-2-using-aiservices-with-deployments-in-parameter-set) -- [Using only defaults](#example-3-using-only-defaults) -- [Using large parameter set](#example-4-using-large-parameter-set) -- [Using `OpenAI` and `deployments` in parameter set with private endpoint](#example-5-using-openai-and-deployments-in-parameter-set-with-private-endpoint) -- [As Speech Service](#example-6-as-speech-service) -- [Using Customer-Managed-Keys with System-Assigned identity](#example-7-using-customer-managed-keys-with-system-assigned-identity) -- [Using Customer-Managed-Keys with User-Assigned identity](#example-8-using-customer-managed-keys-with-user-assigned-identity) -- [WAF-aligned](#example-9-waf-aligned) +- [Storing keys of service in key vault](#example-3-storing-keys-of-service-in-key-vault) +- [Using only defaults](#example-4-using-only-defaults) +- [Using large parameter set](#example-5-using-large-parameter-set) +- [Using `OpenAI` and `deployments` in parameter set with private endpoint](#example-6-using-openai-and-deployments-in-parameter-set-with-private-endpoint) +- [As Speech Service](#example-7-as-speech-service) +- [Using Customer-Managed-Keys with System-Assigned identity](#example-8-using-customer-managed-keys-with-system-assigned-identity) +- [Using Customer-Managed-Keys with User-Assigned identity](#example-9-using-customer-managed-keys-with-user-assigned-identity) +- [WAF-aligned](#example-10-waf-aligned) ### Example 1: _Using `AIServices` with `deployments` in parameter set and private endpoints_ @@ -93,7 +95,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -151,6 +153,48 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'AIServices' +param name = 'csadp003' +// Non-required parameters +param customSubDomainName = 'xcsadpai' +param deployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0301' + } + name: 'gpt-35-turbo' + sku: { + capacity: 10 + name: 'Standard' + } + } +] +param location = '' +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + '' + ] + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +``` + +
    +

    + ### Example 2: _Using `AIServices` with `deployments` in parameter set_ This instance deploys the module with the AI model deployment feature. @@ -193,7 +237,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -237,7 +281,125 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 3: _Using only defaults_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'AIServices' +param name = 'csad002' +// Non-required parameters +param customSubDomainName = 'xcsadai' +param deployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0301' + } + name: 'gpt-35-turbo' + sku: { + capacity: 10 + name: 'Standard' + } + } +] +param location = '' +``` + +
    +

    + +### Example 3: _Storing keys of service in key vault_ + +This instance deploys the module and stores its keys in a key vault. + + +

    + +via Bicep module + +```bicep +module account 'br/public:avm/res/cognitive-services/account:' = { + name: 'accountDeployment' + params: { + // Required parameters + kind: 'SpeechServices' + name: 'csakv001' + // Non-required parameters + location: '' + secretsExportConfiguration: { + accessKey1Name: 'csakv001-accessKey1' + accessKey2Name: 'csakv001-accessKey2' + keyVaultResourceId: '' + } + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "SpeechServices" + }, + "name": { + "value": "csakv001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "accessKey1Name": "csakv001-accessKey1", + "accessKey2Name": "csakv001-accessKey2", + "keyVaultResourceId": "" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csakv001' +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + accessKey1Name: 'csakv001-accessKey1' + accessKey2Name: 'csakv001-accessKey2' + keyVaultResourceId: '' +} +``` + +
    +

    + +### Example 4: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -264,7 +426,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -289,7 +451,24 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 4: _Using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 5: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -426,7 +605,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -581,7 +760,134 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 5: _Using `OpenAI` and `deployments` in parameter set with private endpoint_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'Face' +param name = 'csamax001' +// Non-required parameters +param customSubDomainName = 'xcsamax' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'RequestResponse' + } + { + category: 'Audit' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param networkAcls = { + defaultAction: 'Deny' + ipRules: [ + { + value: '40.74.28.0/23' + } + ] + virtualNetworkRules: [ + { + id: '' + ignoreMissingVnetServiceEndpoint: false + } + ] +} +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.account.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'account' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: 'db64fe2f-3995-4ae0-86ef-97511d5b84e3' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + +### Example 6: _Using `OpenAI` and `deployments` in parameter set with private endpoint_ This instance deploys the module with the AI model deployment feature and private endpoint. @@ -632,7 +938,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -689,7 +995,48 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 6: _As Speech Service_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'OpenAI' +param name = 'csoai002' +// Non-required parameters +param customSubDomainName = 'xcsoaiai' +param deployments = [ + { + model: { + format: 'OpenAI' + name: 'gpt-35-turbo' + version: '0301' + } + name: 'gpt-35-turbo' + sku: { + capacity: 10 + name: 'Standard' + } + } +] +param location = '' +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +``` + +
    +

    + +### Example 7: _As Speech Service_ This instance deploys the module as a Speech Service. @@ -742,7 +1089,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -803,7 +1150,50 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 7: _Using Customer-Managed-Keys with System-Assigned identity_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csaspeech001' +// Non-required parameters +param customSubDomainName = 'speechdomain' +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sku = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + +### Example 8: _Using Customer-Managed-Keys with System-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity. This required the service to be deployed twice, once as a pre-requisite to create the System-Assigned Identity, and once to use it for accessing the Customer-Managed-Key secret. @@ -840,7 +1230,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -885,7 +1275,34 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 8: _Using Customer-Managed-Keys with User-Assigned identity_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = '' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +param publicNetworkAccess = 'Enabled' +param restrictOutboundNetworkAccess = false +param sku = 'S0' +``` + +
    +

    + +### Example 9: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -925,7 +1342,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -973,7 +1390,37 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -### Example 9: _WAF-aligned_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'SpeechServices' +param name = 'csaencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param publicNetworkAccess = 'Enabled' +param restrictOutboundNetworkAccess = false +param sku = 'S0' +``` + +
    +

    + +### Example 10: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1035,7 +1482,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1109,6 +1556,58 @@ module account 'br/public:avm/res/cognitive-services/account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cognitive-services/account:' + +// Required parameters +param kind = 'Face' +param name = 'csawaf001' +// Non-required parameters +param customSubDomainName = 'xcsawaf' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sku = 'S0' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1146,6 +1645,7 @@ module account 'br/public:avm/res/cognitive-services/account:' = { | [`restore`](#parameter-restore) | bool | Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists. | | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | bool | Restrict outbound network access. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | | [`sku`](#parameter-sku) | string | SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`userOwnedStorage`](#parameter-userownedstorage) | array | The storage accounts for this resource. | @@ -1869,6 +2369,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2010,6 +2521,36 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Cognitive Services Contributor'` + - `'Cognitive Services Custom Vision Contributor'` + - `'Cognitive Services Custom Vision Deployment'` + - `'Cognitive Services Custom Vision Labeler'` + - `'Cognitive Services Custom Vision Reader'` + - `'Cognitive Services Custom Vision Trainer'` + - `'Cognitive Services Data Reader (Preview)'` + - `'Cognitive Services Face Recognizer'` + - `'Cognitive Services Immersive Reader User'` + - `'Cognitive Services Language Owner'` + - `'Cognitive Services Language Reader'` + - `'Cognitive Services Language Writer'` + - `'Cognitive Services LUIS Owner'` + - `'Cognitive Services LUIS Reader'` + - `'Cognitive Services LUIS Writer'` + - `'Cognitive Services Metrics Advisor Administrator'` + - `'Cognitive Services Metrics Advisor User'` + - `'Cognitive Services OpenAI Contributor'` + - `'Cognitive Services OpenAI User'` + - `'Cognitive Services QnA Maker Editor'` + - `'Cognitive Services QnA Maker Reader'` + - `'Cognitive Services Speech Contributor'` + - `'Cognitive Services Speech User'` + - `'Cognitive Services User'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** @@ -2101,6 +2642,47 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultResourceId`](#parameter-secretsexportconfigurationkeyvaultresourceid) | string | The key vault name where to store the keys and connection strings generated by the modules. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessKey1Name`](#parameter-secretsexportconfigurationaccesskey1name) | string | The name for the accessKey1 secret to create. | +| [`accessKey2Name`](#parameter-secretsexportconfigurationaccesskey2name) | string | The name for the accessKey2 secret to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The key vault name where to store the keys and connection strings generated by the modules. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.accessKey1Name` + +The name for the accessKey1 secret to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.accessKey2Name` + +The name for the accessKey2 secret to create. + +- Required: No +- Type: string + ### Parameter: `sku` SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. @@ -2151,6 +2733,7 @@ The storage accounts for this resource. | :-- | :-- | :-- | | `endpoint` | string | The service endpoint of the cognitive services account. | | `endpoints` | | All endpoints available for the cognitive services account, types depends on the cognitive service kind. | +| `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the cognitive services account. | | `resourceGroupName` | string | The resource group the cognitive services account was deployed into. | diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 0080ac6d3a..d7c788c144 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -102,6 +102,7 @@ param customerManagedKey customerManagedKeyType @description('Optional. The flag to enable dynamic throttling.') param dynamicThrottlingEnabled bool = false +@secure() @description('Optional. Resource migration token.') param migrationToken string? @@ -123,6 +124,9 @@ param enableTelemetry bool = true @description('Optional. Array of deployments about cognitive service accounts to create.') param deployments deploymentsType +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + var formattedUserAssignedIdentities = reduce( map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), {}, @@ -468,6 +472,36 @@ resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignmen } ] +module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split((secretsExportConfiguration.?keyVaultResourceId ?? '//'), '/')[2], + split((secretsExportConfiguration.?keyVaultResourceId ?? '////'), '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId ?? '//', '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'accessKey1Name') + ? [ + { + name: secretsExportConfiguration!.accessKey1Name + value: cognitiveService.listKeys().key1 + } + ] + : [], + contains(secretsExportConfiguration!, 'accessKey2Name') + ? [ + { + name: secretsExportConfiguration!.accessKey2Name + value: cognitiveService.listKeys().key2 + } + ] + : [] + ) + } +} + @description('The name of the cognitive services account.') output name string = cognitiveService.name @@ -489,6 +523,11 @@ output systemAssignedMIPrincipalId string = cognitiveService.?identity.?principa @description('The location the resource was deployed into.') output location string = cognitiveService.location +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + // ================ // // Definitions // // ================ // @@ -706,3 +745,20 @@ type endpointsType = { @description('The endpoint URI.') endpoint: string? }? + +type secretsExportConfigurationType = { + @description('Required. The key vault name where to store the keys and connection strings generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The name for the accessKey1 secret to create.') + accessKey1Name: string? + + @description('Optional. The name for the accessKey2 secret to create.') + accessKey2Name: string? +} + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 2767bbb995..7f45a5e8dc 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14735378599748380229" + "version": "0.30.23.60470", + "templateHash": "325704537018634474" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -573,6 +573,63 @@ } }, "nullable": true + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." + } + }, + "accessKey1Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey1 secret to create." + } + }, + "accessKey2Name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name for the accessKey2 secret to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } } }, "parameters": { @@ -738,7 +795,7 @@ } }, "migrationToken": { - "type": "string", + "type": "securestring", "nullable": true, "metadata": { "description": "Optional. Resource migration token." @@ -783,6 +840,13 @@ "metadata": { "description": "Optional. Array of deployments about cognitive service accounts to create." } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } } }, "variables": { @@ -1692,6 +1756,140 @@ "dependsOn": [ "cognitiveService" ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '////'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey1Name, 'value', listKeys(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2023-05-01').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey2Name, 'value', listKeys(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '2023-05-01').key2)), createArray()))]" + } + }, + "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.30.23.60470", + "templateHash": "12263717469683062316" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "cognitiveService" + ] } }, "outputs": { @@ -1743,6 +1941,13 @@ "description": "The location the resource was deployed into." }, "value": "[reference('cognitiveService', '2023-05-01', 'full').location]" + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" } } } \ No newline at end of file diff --git a/avm/res/cognitive-services/account/modules/keyVaultExport.bicep b/avm/res/cognitive-services/account/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..d537d2407e --- /dev/null +++ b/avm/res/cognitive-services/account/modules/keyVaultExport.bicep @@ -0,0 +1,62 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the ecrets in.') +param keyVaultName string + +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/cognitive-services/account/tests/e2e/default-with-key-vault/dependencies.bicep b/avm/res/cognitive-services/account/tests/e2e/default-with-key-vault/dependencies.bicep new file mode 100644 index 0000000000..61c051d86d --- /dev/null +++ b/avm/res/cognitive-services/account/tests/e2e/default-with-key-vault/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + enableRbacAuthorization: true + tenantId: subscription().tenantId + } +} + +@description('The name of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/cognitive-services/account/tests/e2e/default-with-key-vault/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/default-with-key-vault/main.test.bicep new file mode 100644 index 0000000000..faeae8df01 --- /dev/null +++ b/avm/res/cognitive-services/account/tests/e2e/default-with-key-vault/main.test.bicep @@ -0,0 +1,63 @@ +targetScope = 'subscription' + +metadata name = 'Storing keys of service in key vault' +metadata description = 'This instance deploys the module and stores its keys in a key vault.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cognitiveservices.accounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'csakv' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + kind: 'SpeechServices' + location: resourceLocation + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + accessKey1Name: '${namePrefix}${serviceShort}001-accessKey1' + accessKey2Name: '${namePrefix}${serviceShort}001-accessKey2' + } + } + } +] diff --git a/avm/res/communication/communication-service/README.md b/avm/res/communication/communication-service/README.md index def24cd565..0ccc24ff39 100644 --- a/avm/res/communication/communication-service/README.md +++ b/avm/res/communication/communication-service/README.md @@ -58,7 +58,7 @@ module communicationService 'br/public:avm/res/communication/communication-servi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,23 @@ module communicationService 'br/public:avm/res/communication/communication-servi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/communication-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ccsmin001' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -161,7 +178,7 @@ module communicationService 'br/public:avm/res/communication/communication-servi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -249,6 +266,74 @@ module communicationService 'br/public:avm/res/communication/communication-servi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/communication-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ccsmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param linkedDomains = [ + '' +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '9237b909-e8fb-4bb8-8194-34aae537cee2' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -289,7 +374,7 @@ module communicationService 'br/public:avm/res/communication/communication-servi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -331,6 +416,36 @@ module communicationService 'br/public:avm/res/communication/communication-servi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/communication-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ccswaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = 'global' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -606,6 +721,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/communication/email-service/README.md b/avm/res/communication/email-service/README.md index 756b60281b..b35ca7f2e6 100644 --- a/avm/res/communication/email-service/README.md +++ b/avm/res/communication/email-service/README.md @@ -59,7 +59,7 @@ module emailService 'br/public:avm/res/communication/email-service:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module emailService 'br/public:avm/res/communication/email-service:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/email-service:' + +// Required parameters +param dataLocation = 'Europe' +param name = 'cesmin001' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -183,7 +200,7 @@ module emailService 'br/public:avm/res/communication/email-service:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -288,6 +305,95 @@ module emailService 'br/public:avm/res/communication/email-service:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/email-service:' + +// Required parameters +param dataLocation = 'United States' +param name = 'cesmax001' +// Non-required parameters +param domains = [ + { + domainManagement: 'AzureManaged' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + name: 'AzureManagedDomain' + roleAssignments: [ + { + name: '1a441bec-9c57-49d1-9a83-b7fd62901413' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + senderUsernames: [ + { + displayName: 'Do Not Reply' + name: 'donotreply' + userName: 'DoNotReply' + } + { + displayName: 'Customer Service' + name: 'customerservice' + userName: 'CustomerService' + } + ] + tags: { + Role: 'DeploymentValidation' + } + userEngagementTracking: 'Enabled' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'bdfa5270-8a55-466d-90d0-b5e96a90fadc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -320,7 +426,7 @@ module emailService 'br/public:avm/res/communication/email-service:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -352,6 +458,28 @@ module emailService 'br/public:avm/res/communication/email-service:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/communication/email-service:' + +// Required parameters +param dataLocation = 'Germany' +param name = 'ceswaf001' +// Non-required parameters +param location = 'global' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -451,6 +579,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/communication/email-service/domain/README.md b/avm/res/communication/email-service/domain/README.md index 20316013ee..e649034df2 100644 --- a/avm/res/communication/email-service/domain/README.md +++ b/avm/res/communication/email-service/domain/README.md @@ -123,6 +123,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/availability-set/README.md b/avm/res/compute/availability-set/README.md index 57229ca6f3..e6ce73d26d 100644 --- a/avm/res/compute/availability-set/README.md +++ b/avm/res/compute/availability-set/README.md @@ -56,7 +56,7 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/availability-set:' + +// Required parameters +param name = 'casmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -133,7 +149,7 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -192,6 +208,51 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/availability-set:' + +// Required parameters +param name = 'casmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param proximityPlacementGroupResourceId = '' +param roleAssignments = [ + { + name: 'd9d13442-232d-4861-9ab9-bad5e90c4f71' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -228,7 +289,7 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -266,6 +327,32 @@ module availabilitySet 'br/public:avm/res/compute/availability-set:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/availability-set:' + +// Required parameters +param name = 'caswaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param proximityPlacementGroupResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -377,6 +464,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine Data Access Administrator (preview)'` + - `'Virtual Machine User Login'` **Required parameters** diff --git a/avm/res/compute/disk-encryption-set/README.md b/avm/res/compute/disk-encryption-set/README.md index eb3e9b657c..aac4301261 100644 --- a/avm/res/compute/disk-encryption-set/README.md +++ b/avm/res/compute/disk-encryption-set/README.md @@ -88,7 +88,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -150,6 +150,52 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdesap001' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -178,7 +224,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -206,6 +252,24 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdesmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -267,7 +331,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -336,6 +400,57 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdesmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'c331c327-6458-473a-9398-95b382c6f04f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -374,7 +489,7 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +531,34 @@ module diskEncryptionSet 'br/public:avm/res/compute/disk-encryption-set:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk-encryption-set:' + +// Required parameters +param keyName = '' +param keyVaultResourceId = '' +param name = 'cdeswaf001' +// Non-required parameters +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -585,6 +728,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/disk/README.md b/avm/res/compute/disk/README.md index be1624c4f6..cdacf8fc53 100644 --- a/avm/res/compute/disk/README.md +++ b/avm/res/compute/disk/README.md @@ -61,7 +61,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,25 @@ module disk 'br/public:avm/res/compute/disk:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 0 +param name = 'cdmin001' +param sku = 'Standard_LRS' +// Non-required parameters +param diskSizeGB = 1 +param location = '' +``` + +
    +

    + ### Example 2: _Using an image_ This instance deploys the module with an image reference. @@ -122,7 +141,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -156,6 +175,26 @@ module disk 'br/public:avm/res/compute/disk:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 0 +param name = 'cdimg001' +param sku = 'Standard_LRS' +// Non-required parameters +param createOption = 'FromImage' +param imageReferenceId = '' +param location = '' +``` + +
    +

    + ### Example 3: _Using an imported image_ This instance deploys the module with a custom image that is imported from a VHD in a storage account. @@ -187,7 +226,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +263,27 @@ module disk 'br/public:avm/res/compute/disk:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 0 +param name = 'cdimp001' +param sku = 'Standard_LRS' +// Non-required parameters +param createOption = 'Import' +param location = '' +param sourceUri = '' +param storageAccountId = '' +``` + +
    +

    + ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -286,7 +346,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -366,6 +426,58 @@ module disk 'br/public:avm/res/compute/disk:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 2 +param name = 'cdmax001' +param sku = 'Premium_LRS' +// Non-required parameters +param diskIOPSReadWrite = 500 +param diskMBpsReadWrite = 60 +param diskSizeGB = 128 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param logicalSectorSize = 512 +param osType = 'Windows' +param publicNetworkAccess = 'Enabled' +param roleAssignments = [ + { + name: '89cc419c-8383-461d-9a70-5cfae4045a8d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -409,7 +521,7 @@ module disk 'br/public:avm/res/compute/disk:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -468,6 +580,39 @@ module disk 'br/public:avm/res/compute/disk:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/disk:' + +// Required parameters +param availabilityZone = 2 +param name = 'cdwaf001' +param sku = 'Premium_LRS' +// Non-required parameters +param diskIOPSReadWrite = 500 +param diskMBpsReadWrite = 60 +param diskSizeGB = 128 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param logicalSectorSize = 512 +param osType = 'Windows' +param publicNetworkAccess = 'Enabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -818,6 +963,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md index 926c7e1b35..46b2362993 100644 --- a/avm/res/compute/gallery/README.md +++ b/avm/res/compute/gallery/README.md @@ -58,7 +58,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/gallery:' + +// Required parameters +param name = 'cgmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -190,7 +206,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = { product: 'testProduct' publisher: 'testPublisher' } - securityType: 'TrustedLaunch' + securityType: 'Standard' vCPUs: { max: 8 min: 2 @@ -311,7 +327,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -420,7 +436,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = { "product": "testProduct", "publisher": "testPublisher" }, - "securityType": "TrustedLaunch", + "securityType": "Standard", "vCPUs": { "max": 8, "min": 2 @@ -548,6 +564,227 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/gallery:' + +// Required parameters +param name = 'cgmax001' +// Non-required parameters +param applications = [ + { + name: 'cgmax-appd-001' + supportedOSType: 'Linux' + } + { + name: 'cgmax-appd-002' + roleAssignments: [ + { + name: '4ef8d3d3-54be-4522-92c3-284977292d87' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + supportedOSType: 'Windows' + } +] +param images = [ + { + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V1' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } + name: 'az-imgd-ws-001' + osState: 'Generalized' + osType: 'Windows' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName1' + product: 'testProduct1' + publisher: 'testPublisher1' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + } + { + hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition-hibernate' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-ws-002' + osState: 'Generalized' + osType: 'Windows' + vCPUs: { + max: 8 + min: 2 + } + } + { + hyperVGeneration: 'V2' + identifier: { + offer: 'WindowsDesktop' + publisher: 'MicrosoftWindowsDesktop' + sku: 'Win11-21H2' + } + memory: { + max: 16 + min: 4 + } + name: 'az-imgd-wdtl-003' + osState: 'Generalized' + osType: 'Windows' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + securityType: 'Standard' + vCPUs: { + max: 8 + min: 2 + } + } + { + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '22_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-004' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } + } + { + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-minimal-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-005' + osState: 'Generalized' + osType: 'Linux' + vCPUs: { + max: 4 + min: 1 + } + } + { + architecture: 'x64' + description: 'testDescription' + endOfLife: '2033-01-01' + eula: 'test Eula' + excludedDiskTypes: [ + 'Standard_LRS' + ] + hyperVGeneration: 'V2' + identifier: { + offer: '0001-com-ubuntu-server-focal' + publisher: 'canonical' + sku: '20_04-lts-gen2' + } + isAcceleratedNetworkSupported: false + isHibernateSupported: true + memory: { + max: 32 + min: 4 + } + name: 'az-imgd-us-006' + osState: 'Generalized' + osType: 'Linux' + privacyStatementUri: 'https://testPrivacyStatementUri.com' + purchasePlan: { + name: 'testPlanName' + product: 'testProduct' + publisher: 'testPublisher' + } + releaseNoteUri: 'https://testReleaseNoteUri.com' + securityType: 'TrustedLaunch' + vCPUs: { + max: 4 + min: 1 + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '3bd58a78-108d-4f87-b404-0a03e49303d8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -597,7 +834,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -648,6 +885,45 @@ module gallery 'br/public:avm/res/compute/gallery:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/gallery:' + +// Required parameters +param name = 'cgwaf001' +// Non-required parameters +param applications = [ + { + name: 'cgwaf-appd-001' + supportedOSType: 'Windows' + } +] +param images = [ + { + identifier: { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + } + name: 'az-imgd-ws-001' + osState: 'Generalized' + osType: 'Windows' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -967,6 +1243,8 @@ The security type of the image. Requires a hyperVGeneration V2. Defaults to `Sta 'ConfidentialVMSupported' 'Standard' 'TrustedLaunch' + 'TrustedLaunchAndConfidentialVmSupported' + 'TrustedLaunchSupported' ] ``` @@ -1048,6 +1326,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/gallery/application/README.md b/avm/res/compute/gallery/application/README.md index be70237005..879fb1c1db 100644 --- a/avm/res/compute/gallery/application/README.md +++ b/avm/res/compute/gallery/application/README.md @@ -129,6 +129,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/gallery/application/main.json b/avm/res/compute/gallery/application/main.json index bdc767825b..42db0c54ff 100644 --- a/avm/res/compute/gallery/application/main.json +++ b/avm/res/compute/gallery/application/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7960057132021914503" + "version": "0.30.23.60470", + "templateHash": "13081960860160182257" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", diff --git a/avm/res/compute/gallery/image/README.md b/avm/res/compute/gallery/image/README.md index 98d3d3ec68..c8ee79aeb5 100644 --- a/avm/res/compute/gallery/image/README.md +++ b/avm/res/compute/gallery/image/README.md @@ -321,6 +321,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Compute Gallery Sharing Admin'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -425,6 +432,8 @@ The security type of the image. Requires a hyperVGeneration V2. 'ConfidentialVMSupported' 'Standard' 'TrustedLaunch' + 'TrustedLaunchAndConfidentialVmSupported' + 'TrustedLaunchSupported' ] ``` diff --git a/avm/res/compute/gallery/image/main.bicep b/avm/res/compute/gallery/image/main.bicep index 808b755df2..f719228f82 100644 --- a/avm/res/compute/gallery/image/main.bicep +++ b/avm/res/compute/gallery/image/main.bicep @@ -39,7 +39,13 @@ param memory resourceRangeType = { min: 4, max: 16 } param releaseNoteUri string? @sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2.') -param securityType ('Standard' | 'TrustedLaunch' | 'ConfidentialVM' | 'ConfidentialVMSupported')? +param securityType ( + | 'Standard' + | 'ConfidentialVM' + | 'TrustedLaunchSupported' + | 'TrustedLaunch' + | 'TrustedLaunchAndConfidentialVmSupported' + | 'ConfidentialVMSupported')? @sys.description('Optional. Specify if the image supports accelerated networking.') param isAcceleratedNetworkSupported bool = true @@ -132,7 +138,7 @@ resource image 'Microsoft.Compute/galleries/images@2023-07-03' = { value: '${isAcceleratedNetworkSupported}' } ], - (securityType != null + (securityType != null && securityType != 'Standard' // Standard is the default and is not set ? [ { name: 'SecurityType' diff --git a/avm/res/compute/gallery/image/main.json b/avm/res/compute/gallery/image/main.json index 941b51a87c..aede5e97ac 100644 --- a/avm/res/compute/gallery/image/main.json +++ b/avm/res/compute/gallery/image/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17284709546040050431" + "version": "0.30.23.60470", + "templateHash": "5984025187928110337" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -275,7 +275,9 @@ "ConfidentialVM", "ConfidentialVMSupported", "Standard", - "TrustedLaunch" + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" ], "nullable": true, "metadata": { @@ -399,7 +401,7 @@ }, "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(and(not(equals(parameters('securityType'), null())), not(equals(parameters('securityType'), 'Standard'))), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", "identifier": { "publisher": "[parameters('identifier').publisher]", diff --git a/avm/res/compute/gallery/main.bicep b/avm/res/compute/gallery/main.bicep index b93b444a27..44ed9c41f6 100644 --- a/avm/res/compute/gallery/main.bicep +++ b/avm/res/compute/gallery/main.bicep @@ -214,6 +214,7 @@ output imageResourceIds array = [ // Definitions // // =============== // +@export() type lockType = { @sys.description('Optional. Specify the name of lock.') name: string? @@ -222,6 +223,7 @@ type lockType = { kind: ('CanNotDelete' | 'ReadOnly' | 'None')? } +@export() type roleAssignmentType = { @sys.description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') name: string? @@ -249,6 +251,8 @@ type roleAssignmentType = { }[] import { identifierType, purchasePlanType, resourceRangeType } from './image/main.bicep' + +@export() type imageType = { @sys.description('Required. Name of the image definition.') @minLength(1) @@ -277,7 +281,13 @@ type imageType = { hyperVGeneration: ('V1' | 'V2')? @sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2. Defaults to `Standard`.') - securityType: ('Standard' | 'TrustedLaunch' | 'ConfidentialVM' | 'ConfidentialVMSupported')? + securityType: ( + | 'Standard' + | 'ConfidentialVM' + | 'TrustedLaunchSupported' + | 'TrustedLaunch' + | 'TrustedLaunchAndConfidentialVmSupported' + | 'ConfidentialVMSupported')? @sys.description('Optional. Specify if the image supports accelerated networking. Defaults to true.') isAcceleratedNetworkSupported: bool? diff --git a/avm/res/compute/gallery/main.json b/avm/res/compute/gallery/main.json index d0346696e2..d2b8bfe98a 100644 --- a/avm/res/compute/gallery/main.json +++ b/avm/res/compute/gallery/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16056066182123599311" + "version": "0.30.23.60470", + "templateHash": "17783194818453553981" }, "name": "Azure Compute Galleries", "description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).", @@ -35,6 +35,9 @@ "description": "Optional. Specify the type of lock." } } + }, + "metadata": { + "__bicep_export!": true } }, "roleAssignmentType": { @@ -107,6 +110,9 @@ } } } + }, + "metadata": { + "__bicep_export!": true } }, "imageType": { @@ -184,7 +190,9 @@ "ConfidentialVM", "ConfidentialVMSupported", "Standard", - "TrustedLaunch" + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" ], "nullable": true, "metadata": { @@ -261,6 +269,9 @@ "description": "Optional. Describes the disallowed disk types." } } + }, + "metadata": { + "__bicep_export!": true } }, "identifierType": { @@ -573,8 +584,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7960057132021914503" + "version": "0.30.23.60470", + "templateHash": "13081960860160182257" }, "name": "Compute Galleries Applications", "description": "This module deploys an Azure Compute Gallery Application.", @@ -934,8 +945,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17284709546040050431" + "version": "0.30.23.60470", + "templateHash": "5984025187928110337" }, "name": "Compute Galleries Image Definitions", "description": "This module deploys an Azure Compute Gallery Image Definition.", @@ -1204,7 +1215,9 @@ "ConfidentialVM", "ConfidentialVMSupported", "Standard", - "TrustedLaunch" + "TrustedLaunch", + "TrustedLaunchAndConfidentialVmSupported", + "TrustedLaunchSupported" ], "nullable": true, "metadata": { @@ -1328,7 +1341,7 @@ }, "endOfLifeDate": "[parameters('endOfLifeDate')]", "eula": "[parameters('eula')]", - "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(not(equals(parameters('securityType'), null())), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", + "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported')))), if(and(not(equals(parameters('securityType'), null())), not(equals(parameters('securityType'), 'Standard'))), createArray(createObject('name', 'SecurityType', 'value', format('{0}', parameters('securityType')))), createArray()), if(not(equals(parameters('isHibernateSupported'), null())), createArray(createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), createArray()))]", "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(coalesce(parameters('securityType'), ''))), 'V2', 'V1'))]", "identifier": { "publisher": "[parameters('identifier').publisher]", diff --git a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep index f094c884e9..a29b6ff7c8 100644 --- a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep +++ b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep @@ -135,7 +135,7 @@ module testDeployment '../../../main.bicep' = [ } { name: '${namePrefix}-az-imgd-wdtl-003' - securityType: 'TrustedLaunch' + securityType: 'Standard' osType: 'Windows' osState: 'Generalized' hyperVGeneration: 'V2' diff --git a/avm/res/compute/image/README.md b/avm/res/compute/image/README.md index 786bf30b97..b4fd5878bc 100644 --- a/avm/res/compute/image/README.md +++ b/avm/res/compute/image/README.md @@ -59,7 +59,7 @@ module image 'br/public:avm/res/compute/image:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,26 @@ module image 'br/public:avm/res/compute/image:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/image:' + +// Required parameters +param name = 'cimin001' +param osAccountType = 'Standard_LRS' +param osDiskBlobUri = '' +param osDiskCaching = 'ReadWrite' +param osType = 'Windows' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -152,7 +172,7 @@ module image 'br/public:avm/res/compute/image:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -229,6 +249,55 @@ module image 'br/public:avm/res/compute/image:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/image:' + +// Required parameters +param name = 'cimax001' +param osAccountType = 'Premium_LRS' +param osDiskBlobUri = '' +param osDiskCaching = 'ReadWrite' +param osType = 'Windows' +// Non-required parameters +param diskEncryptionSetResourceId = '' +param diskSizeGB = 128 +param hyperVGeneration = 'V1' +param location = '' +param osState = 'Generalized' +param roleAssignments = [ + { + name: '2dfcdedd-220c-4b6b-b8bd-58e22e0c5434' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneResilient = true +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -269,7 +338,7 @@ module image 'br/public:avm/res/compute/image:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -325,6 +394,36 @@ module image 'br/public:avm/res/compute/image:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/image:' + +// Required parameters +param name = 'ciwaf001' +param osAccountType = 'Premium_LRS' +param osDiskBlobUri = '' +param osDiskCaching = 'ReadWrite' +param osType = 'Windows' +// Non-required parameters +param diskEncryptionSetResourceId = '' +param diskSizeGB = 128 +param hyperVGeneration = 'V1' +param location = '' +param osState = 'Generalized' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneResilient = true +``` + +
    +

    + ## Parameters **Required parameters** @@ -476,6 +575,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/proximity-placement-group/README.md b/avm/res/compute/proximity-placement-group/README.md index 849182b03d..5da6adc55e 100644 --- a/avm/res/compute/proximity-placement-group/README.md +++ b/avm/res/compute/proximity-placement-group/README.md @@ -56,7 +56,7 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/proximity-placement-group:' + +// Required parameters +param name = 'cppgmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -148,7 +164,7 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

    -via JSON Parameter file +via JSON parameters file ```json { @@ -228,6 +244,66 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/proximity-placement-group:' + +// Required parameters +param name = 'cppgmax001' +// Non-required parameters +param colocationStatus = { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' +} +param intent = { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '9e0b6b99-ff4b-4c99-a2ce-3a2a1a880874' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' +} +param type = 'Standard' +param zones = [ + '1' +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -275,7 +351,7 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

    -via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +404,43 @@ module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-gr

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/proximity-placement-group:' + +// Required parameters +param name = 'cppgwaf001' +// Non-required parameters +param colocationStatus = { + code: 'ColocationStatus/Aligned' + displayStatus: 'Aligned' + level: 'Info' + message: 'I\'m a default error message' +} +param intent = { + vmSizes: [ + 'Standard_B1ms' + 'Standard_B4ms' + ] +} +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + TagA: 'Would you kindly...' + TagB: 'Tags for sale' +} +param type = 'Standard' +param zones = [ + '1' +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -429,6 +542,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/ssh-public-key/README.md b/avm/res/compute/ssh-public-key/README.md index 6db199cbfd..0edc87a245 100644 --- a/avm/res/compute/ssh-public-key/README.md +++ b/avm/res/compute/ssh-public-key/README.md @@ -18,7 +18,7 @@ This module deploys a Public SSH Key. | :-- | :-- | | `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.Compute/sshPublicKeys` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2023-07-01/sshPublicKeys) | +| `Microsoft.Compute/sshPublicKeys` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-01/sshPublicKeys) | ## Usage examples @@ -58,7 +58,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/ssh-public-key:' + +// Required parameters +param name = 'cspkmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -136,7 +152,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -198,6 +214,52 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/ssh-public-key:' + +// Required parameters +param name = 'sshkey-cspkmax001' +// Non-required parameters +param enableTelemetry = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param publicKey = '' +param roleAssignments = [ + { + name: '74ec0421-c3f4-46f2-acf0-b519fe6fcf1c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -252,7 +314,7 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -312,6 +374,50 @@ module sshPublicKey 'br/public:avm/res/compute/ssh-public-key:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/ssh-public-key:' + +// Required parameters +param name = 'sshkey-cspkwaf001' +// Non-required parameters +param enableTelemetry = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param publicKey = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -403,6 +509,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/compute/ssh-public-key/main.bicep b/avm/res/compute/ssh-public-key/main.bicep index 69ab8ddac2..0292a5ffe2 100644 --- a/avm/res/compute/ssh-public-key/main.bicep +++ b/avm/res/compute/ssh-public-key/main.bicep @@ -70,7 +70,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource sshPublicKey 'Microsoft.Compute/sshPublicKeys@2023-07-01' = { +resource sshPublicKey 'Microsoft.Compute/sshPublicKeys@2024-03-01' = { name: name location: location tags: tags diff --git a/avm/res/compute/ssh-public-key/main.json b/avm/res/compute/ssh-public-key/main.json index a24878491e..6bb1479682 100644 --- a/avm/res/compute/ssh-public-key/main.json +++ b/avm/res/compute/ssh-public-key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8431280172894888036" + "version": "0.30.23.60470", + "templateHash": "5428269336337327866" }, "name": "Public SSH Keys", "description": "This module deploys a Public SSH Key.\n\n> Note: The resource does not auto-generate the key for you.", @@ -199,7 +199,7 @@ }, "sshPublicKey": { "type": "Microsoft.Compute/sshPublicKeys", - "apiVersion": "2023-07-01", + "apiVersion": "2024-03-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "tags": "[parameters('tags')]", @@ -271,7 +271,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('sshPublicKey', '2023-07-01', 'full').location]" + "value": "[reference('sshPublicKey', '2024-03-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/compute/virtual-machine-scale-set/README.md b/avm/res/compute/virtual-machine-scale-set/README.md index 730b23f033..123eb0d315 100644 --- a/avm/res/compute/virtual-machine-scale-set/README.md +++ b/avm/res/compute/virtual-machine-scale-set/README.md @@ -102,7 +102,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    -via JSON Parameter file +via JSON parameters file ```json { @@ -181,6 +181,63 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminUsername = 'scaleSetAdmin' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmsslinmin001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmin' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param skuName = 'Standard_B12ms' +// Non-required parameters +param disablePasswordAuthentication = true +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } +] +``` + +
    +

    + ### Example 2: _Using large parameter set for Linux_ This instance deploys the module with most of its features enabled. @@ -358,7 +415,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    -via JSON Parameter file +via JSON parameters file ```json { @@ -585,6 +642,173 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminUsername = 'scaleSetAdmin' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmsslinmax001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param skuName = 'Standard_B12ms' +// Non-required parameters +param availabilityZones = [ + '2' +] +param bootDiagnosticStorageAccountName = '' +param dataDisks = [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '256' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disablePasswordAuthentication = true +param encryptionAtHost = false +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: 'sudo apt-get update' + } +} +param extensionDependencyAgentConfig = { + enabled: true +} +param extensionMonitoringAgentConfig = { + enabled: true +} +param extensionNetworkWatcherAgentConfig = { + enabled: true +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param publicKeys = [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } +] +param roleAssignments = [ + { + name: '8abf72f9-e918-4adc-b20b-c783b8799065' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scaleSetFaultDomain = 1 +param skuCapacity = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param upgradePolicyMode = 'Manual' +param vmNamePrefix = 'vmsslinvm' +param vmPriority = 'Regular' +``` + +
    +

    + ### Example 3: _Using disk encryption set for the VM._ This instance deploys the module with disk enryption set. @@ -671,7 +895,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    -via JSON Parameter file +via JSON parameters file ```json { @@ -773,6 +997,82 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminUsername = 'scaleSetAdmin' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmsslcmk001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsslcmk' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param skuName = 'Standard_B12ms' +// Non-required parameters +param dataDisks = [ + { + caching: 'ReadOnly' + createOption: 'Empty' + diskSizeGB: '128' + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } +] +param disablePasswordAuthentication = true +param extensionMonitoringAgentConfig = { + enabled: true +} +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/scaleSetAdmin/.ssh/authorized_keys' + } +] +``` + +
    +

    + ### Example 4: _Using only defaults for Windows_ This instance deploys the module with the minimum set of required parameters. @@ -834,7 +1134,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    -via JSON Parameter file +via JSON parameters file ```json { @@ -905,6 +1205,57 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmsswinmin001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmin' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param skuName = 'Standard_B12ms' +// Non-required parameters +param adminPassword = '' +param location = '' +``` + +
    +

    + ### Example 5: _Using large parameter set for Windows_ This instance deploys the module with most of its features enabled. @@ -1082,7 +1433,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1305,6 +1656,173 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmsswinmax001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinmax' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param skuName = 'Standard_B12ms' +// Non-required parameters +param adminPassword = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param encryptionAtHost = false +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: '' + } +} +param extensionDependencyAgentConfig = { + enabled: true +} +param extensionDSCConfig = { + enabled: true +} +param extensionHealthConfig = { + enabled: true + settings: { + port: 80 + protocol: 'http' + requestPath: '/' + } +} +param extensionMonitoringAgentConfig = { + enabled: true +} +param extensionNetworkWatcherAgentConfig = { + enabled: true +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '1910de8c-4dab-4189-96bb-2feb68350fb8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param upgradePolicyMode = 'Manual' +param vmNamePrefix = 'vmsswinvm' +param vmPriority = 'Regular' +``` + +
    +

    + ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework for Windows. @@ -1451,7 +1969,7 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1637,6 +2155,142 @@ module virtualMachineScaleSet 'br/public:avm/res/compute/virtual-machine-scale-s

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine-scale-set:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmsswinwaf001' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddressConfiguration: { + name: 'pip-cvmsswinwaf' + } + subnet: { + id: '' + } + } + } + ] + nicSuffix: '-nic01' + } +] +param osDisk = { + createOption: 'fromImage' + diskSizeGB: '128' + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param skuName = 'Standard_B12ms' +// Non-required parameters +param adminPassword = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param encryptionAtHost = false +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: true + Exclusions: { + Extensions: '.log;.ldf' + Paths: 'D:\\IISlogs;D:\\DatabaseLogs' + Processes: 'mssence.svc' + } + RealtimeProtectionEnabled: true + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + protectedSettings: { + commandToExecute: '' + } +} +param extensionDependencyAgentConfig = { + enabled: true +} +param extensionDSCConfig = { + enabled: true +} +param extensionMonitoringAgentConfig = { + enabled: true +} +param extensionNetworkWatcherAgentConfig = { + enabled: true +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param skuCapacity = 1 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param upgradePolicyMode = 'Manual' +param vmNamePrefix = 'vmsswinvm' +param vmPriority = 'Regular' +``` + +
    +

    + ## Parameters **Required parameters** @@ -2450,6 +3104,25 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Desktop Virtualization Power On Contributor'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'DevTest Labs User'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine User Login'` + - `'VM Scanner Operator'` **Required parameters** diff --git a/avm/res/compute/virtual-machine/README.md b/avm/res/compute/virtual-machine/README.md index f34080a1bc..16a4e92bf0 100644 --- a/avm/res/compute/virtual-machine/README.md +++ b/avm/res/compute/virtual-machine/README.md @@ -19,7 +19,7 @@ This module deploys a Virtual Machine with one or multiple NICs and optionally o | `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.Automanage/configurationProfileAssignments` | [2022-05-04](https://learn.microsoft.com/en-us/azure/templates) | -| `Microsoft.Compute/virtualMachines` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-03-01/virtualMachines) | +| `Microsoft.Compute/virtualMachines` | [2024-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2024-07-01/virtualMachines) | | `Microsoft.Compute/virtualMachines/extensions` | [2022-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Compute/2022-11-01/virtualMachines/extensions) | | `Microsoft.DevTestLab/schedules` | [2018-09-15](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DevTestLab/2018-09-15/schedules) | | `Microsoft.GuestConfiguration/guestConfigurationAssignments` | [2020-06-25](https://learn.microsoft.com/en-us/azure/templates/Microsoft.GuestConfiguration/2020-06-25/guestConfigurationAssignments) | @@ -98,7 +98,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters configurationProfile: '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' @@ -119,7 +119,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -174,7 +174,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Linux" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -204,6 +204,65 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmlinatmg' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param configurationProfile = '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' +param disablePasswordAuthentication = true +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/localAdminUser/.ssh/authorized_keys' + } +] +``` + +
    +

    + ### Example 2: _Using only defaults for Linux_ This instance deploys the module with the minimum set of required parameters. @@ -248,7 +307,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters disablePasswordAuthentication: true @@ -268,7 +327,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -319,7 +378,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Linux" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -346,6 +405,60 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: '0001-com-ubuntu-server-jammy' + publisher: 'Canonical' + sku: '22_04-lts-gen2' + version: 'latest' +} +param name = 'cvmlinmin' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + name: 'pip-01' + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Linux' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param disablePasswordAuthentication = true +param location = '' +param publicKeys = [ + { + keyData: '' + path: '/home/localAdminUser/.ssh/authorized_keys' + } +] +``` + +
    +

    + ### Example 3: _Using large parameter set for Linux_ This instance deploys the module with most of its features enabled. @@ -473,7 +586,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { name: 'osdisk01' } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 1 // Non-required parameters backupPolicyName: '' @@ -639,7 +752,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -773,7 +886,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Linux" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 1 @@ -988,6 +1101,289 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdministrator' +param imageReference = { + offer: '0001-com-ubuntu-server-focal' + publisher: 'Canonical' + sku: '' + version: 'latest' +} +param name = 'cvmlinmax' +param nicConfigurations = [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + name: '696e6067-3ddc-4b71-bf97-9caebeba441a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: 'ff72f58d-a3cf-42fd-9c27-c61906bdddfe' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +param osDisk = { + caching: 'ReadOnly' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'osdisk01' +} +param osType = 'Linux' +param vmSize = 'Standard_D2s_v3' +param zone = 1 +// Non-required parameters +param backupPolicyName = '' +param backupVaultName = '' +param backupVaultResourceGroup = '' +param computerName = 'linvm1' +param dataDisks = [ + { + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk01' + } + { + caching: 'ReadWrite' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk02' + } +] +param disablePasswordAuthentication = true +param enableAutomaticUpdates = true +param encryptionAtHost = false +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + VolumeType: 'All' + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptProtectedSetting = { + commandToExecute: '' +} +param extensionDependencyAgentConfig = { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionDSCConfig = { + enabled: false + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionMonitoringAgentConfig = { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionNetworkWatcherAgentConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param patchMode = 'AutomaticByPlatform' +param publicKeys = [ + { + keyData: '' + path: '/home/localAdministrator/.ssh/authorized_keys' + } +] +param rebootSetting = 'IfRequired' +param roleAssignments = [ + { + name: 'eb01de52-d2be-4272-a7b9-13de6c399e27' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework for Windows. @@ -1092,7 +1488,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 2 // Non-required parameters adminPassword: '' @@ -1273,7 +1669,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1384,7 +1780,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 2 @@ -1618,6 +2014,281 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'VMAdmin' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' +} +param name = 'cvmwinwaf' +param nicConfigurations = [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + zones: [ + 1 + 2 + 3 + ] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } +] +param osDisk = { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 2 +// Non-required parameters +param adminPassword = '' +param backupPolicyName = '' +param backupVaultName = '' +param backupVaultResourceGroup = '' +param bypassPlatformSafetyChecksOnUserSchedule = true +param computerName = 'winvm1' +param dataDisks = [ + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } + { + caching: 'ReadOnly' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + } +] +param enableAutomaticUpdates = true +param encryptionAtHost = false +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptProtectedSetting = { + commandToExecute: '' +} +param extensionDependencyAgentConfig = { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionDSCConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionMonitoringAgentConfig = { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionNetworkWatcherAgentConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maintenanceConfigurationResourceId = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param patchMode = 'AutomaticByPlatform' +param proximityPlacementGroupResourceId = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 5: _Using only defaults for Windows_ This instance deploys the module with the minimum set of required parameters. @@ -1659,7 +2330,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -1673,7 +2344,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1721,7 +2392,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -1740,6 +2411,51 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinmin' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param location = '' +``` + +
    +

    + ### Example 6: _Using guest configuration for Windows_ This instance deploys the module with the a guest configuration. @@ -1767,6 +2483,10 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { ipConfigurations: [ { name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } subnetResourceId: '' } ] @@ -1781,7 +2501,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -1824,7 +2544,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1852,6 +2572,10 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "ipConfigurations": [ { "name": "ipconfig01", + "pipConfiguration": { + "publicIpNameSuffix": "-pip-01", + "zones": [] + }, "subnetResourceId": "" } ], @@ -1872,7 +2596,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -1926,6 +2650,84 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinguest' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param extensionGuestConfigurationExtension = { + enabled: true +} +param guestConfiguration = { + assignmentType: 'ApplyAndMonitor' + configurationParameter: [ + { + name: 'Minimum Password Length;ExpectedValue' + value: '16' + } + { + name: 'Minimum Password Length;RemediateValue' + value: '16' + } + { + name: 'Maximum Password Age;ExpectedValue' + value: '75' + } + { + name: 'Maximum Password Age;RemediateValue' + value: '75' + } + ] + name: 'AzureWindowsBaseline' + version: '1.*' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
    +

    + ### Example 7: _Using a host pool to register the VM_ This instance deploys the module and registers it in a host pool. @@ -1967,7 +2769,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -2004,7 +2806,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2052,7 +2854,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -2100,6 +2902,74 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinhp' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionHostPoolRegistration = { + configurationFunction: 'Configuration.ps1\\AddSessionHost' + enabled: true + hostPoolName: '' + modulesUrl: '' + registrationInfoToken: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
    +

    + ### Example 8: _Using large parameter set for Windows_ This instance deploys the module with most of its features enabled. @@ -2168,7 +3038,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { ] name: 'ipconfig01' pipConfiguration: { - publicIpNameSuffix: '-pip-01' + publicIPAddressResourceId: '' roleAssignments: [ { name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' @@ -2187,11 +3057,6 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { roleDefinitionIdOrName: '' } ] - zones: [ - 1 - 2 - 3 - ] } subnetResourceId: '' } @@ -2228,7 +3093,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { name: 'osdisk01' } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 2 // Non-required parameters adminPassword: '' @@ -2423,7 +3288,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2492,7 +3357,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { ], "name": "ipconfig01", "pipConfiguration": { - "publicIpNameSuffix": "-pip-01", + "publicIPAddressResourceId": "", "roleAssignments": [ { "name": "e962e7c1-261a-4afd-b5ad-17a640a0b7bc", @@ -2510,11 +3375,6 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "principalType": "ServicePrincipal", "roleDefinitionIdOrName": "" } - ], - "zones": [ - 1, - 2, - 3 ] }, "subnetResourceId": "" @@ -2558,7 +3418,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 2 @@ -2806,6 +3666,314 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'VMAdmin' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' +} +param name = 'cvmwinmax' +param nicConfigurations = [ + { + deleteOption: 'Delete' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableIPForwarding: true + ipConfigurations: [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + pipConfiguration: { + publicIPAddressResourceId: '' + roleAssignments: [ + { + name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + subnetResourceId: '' + } + ] + name: 'nic-test-01' + roleAssignments: [ + { + name: '95fc1cc2-05ed-4f5a-a22c-a6ca852df7e7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +param osDisk = { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'osdisk01' +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 2 +// Non-required parameters +param adminPassword = '' +param autoShutdownConfig = { + dailyRecurrenceTime: '19:00' + notificationEmail: 'test@contoso.com' + notificationLocale: 'en' + notificationStatus: 'Enabled' + notificationTimeInMinutes: 30 + status: 'Enabled' + timeZone: 'UTC' +} +param backupPolicyName = '' +param backupVaultName = '' +param backupVaultResourceGroup = '' +param computerName = 'winvm1' +param dataDisks = [ + { + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + lun: 0 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk01' + } + { + caching: 'None' + createOption: 'Empty' + deleteOption: 'Delete' + diskSizeGB: 128 + lun: 1 + managedDisk: { + storageAccountType: 'Premium_LRS' + } + name: 'datadisk02' + } +] +param enableAutomaticUpdates = true +param encryptionAtHost = false +param extensionAadJoinConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAntiMalwareConfig = { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: { + Extensions: '.ext1;.ext2' + Paths: 'c:\\excluded-path-1;c:\\excluded-path-2' + Processes: 'excludedproc1.exe;excludedproc2.exe' + } + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionAzureDiskEncryptionConfig = { + enabled: true + settings: { + EncryptionOperation: 'EnableEncryption' + KekVaultResourceId: '' + KeyEncryptionAlgorithm: 'RSA-OAEP' + KeyEncryptionKeyURL: '' + KeyVaultResourceId: '' + KeyVaultURL: '' + ResizeOSDisk: 'false' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + VolumeType: 'All' + } +} +param extensionCustomScriptConfig = { + enabled: true + fileData: [ + { + storageAccountId: '' + uri: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionCustomScriptProtectedSetting = { + commandToExecute: '' +} +param extensionDependencyAgentConfig = { + enableAMA: true + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionDSCConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionMonitoringAgentConfig = { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: '' + name: 'SendMetricsToLAW' + } + ] + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param extensionNetworkWatcherAgentConfig = { + enabled: true + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param patchMode = 'AutomaticByPlatform' +param proximityPlacementGroupResourceId = '' +param rebootSetting = 'IfRequired' +param roleAssignments = [ + { + name: 'c70e8c48-6945-4607-9695-1098ba5a86ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 9: _Deploy a VM with nVidia graphic card_ This instance deploys the module for a VM with dedicated nVidia graphic card. @@ -2864,7 +4032,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2936,6 +4104,54 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinnv' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_NV6ads_A10_v5' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param extensionNvidiaGpuDriverWindows = { + enabled: true +} +param location = '' +``` + +
    +

    + ### Example 10: _Using disk encryption set for the VM._ This instance deploys the module with disk enryption set. @@ -2979,7 +4195,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -3004,7 +4220,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -3054,7 +4270,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -3086,6 +4302,64 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'VMAdministrator' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2019-datacenter' + version: 'latest' +} +param name = 'cvmwincmk' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param dataDisks = [ + { + diskSizeGB: 128 + managedDisk: { + diskEncryptionSet: { + id: '' + } + storageAccountType: 'Premium_LRS' + } + } +] +param location = '' +``` + +
    +

    + ### Example 11: _Adding the VM to a VMSS._ This instance deploys the module with the minimum set of required parameters and adds it to a VMSS. @@ -3127,7 +4401,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 0 // Non-required parameters adminPassword: '' @@ -3142,7 +4416,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -3190,7 +4464,7 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = { "value": "Windows" }, "vmSize": { - "value": "Standard_DS2_v2" + "value": "Standard_D2s_v3" }, "zone": { "value": 0 @@ -3212,6 +4486,52 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/compute/virtual-machine:' + +// Required parameters +param adminUsername = 'localAdminUser' +param imageReference = { + offer: 'WindowsServer' + publisher: 'MicrosoftWindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' +} +param name = 'cvmwinvmss' +param nicConfigurations = [ + { + ipConfigurations: [ + { + name: 'ipconfig01' + subnetResourceId: '' + } + ] + nicSuffix: '-nic-01' + } +] +param osDisk = { + caching: 'ReadWrite' + diskSizeGB: 128 + managedDisk: { + storageAccountType: 'Premium_LRS' + } +} +param osType = 'Windows' +param vmSize = 'Standard_D2s_v3' +param zone = 0 +// Non-required parameters +param adminPassword = '' +param location = '' +param virtualMachineScaleSetResourceId = '' +``` + +
    +

    + ## Parameters **Required parameters** @@ -4210,6 +5530,25 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Operator for Managed Disks'` + - `'Desktop Virtualization Power On Contributor'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'DevTest Labs User'` + - `'Disk Backup Reader'` + - `'Disk Pool Operator'` + - `'Disk Restore Operator'` + - `'Disk Snapshot Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Administrator Login'` + - `'Virtual Machine Contributor'` + - `'Virtual Machine User Login'` + - `'VM Scanner Operator'` **Required parameters** @@ -4404,11 +5743,13 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/network-interface:0.2.4` | Remote reference | -| `br/public:avm/res/network/public-ip-address:0.4.1` | Remote reference | +| `br/public:avm/res/network/network-interface:0.4.0` | Remote reference | +| `br/public:avm/res/network/public-ip-address:0.6.0` | Remote reference | ## Notes +Inside the `nicConfigurations` section and there inside the `ipConfigurations`, a `pipConfiguration` can be defined. For a new puplic IP address, the naming can either be set with the `name` or the `publicIpNameSuffix`. Per default a newly created PIP will have its `zones` parameter set to `[1,2,3]`. You can override it, for example with `[]`. If an existing PIP should be used, only set the `publicIPAddressResourceId`. + ### Automanage considerations Enabling automanage triggers the creation of additional resources outside of the specific virtual machine deployment, such as: diff --git a/avm/res/compute/virtual-machine/main.bicep b/avm/res/compute/virtual-machine/main.bicep index 1b92cfe376..d9f22a1b23 100644 --- a/avm/res/compute/virtual-machine/main.bicep +++ b/avm/res/compute/virtual-machine/main.bicep @@ -478,21 +478,15 @@ module vm_nic 'modules/nic-configuration.bicep' = [ for (nicConfiguration, index) in nicConfigurations: { name: '${uniqueString(deployment().name, location)}-VM-Nic-${index}' params: { - networkInterfaceName: contains(nicConfiguration, 'name') - ? nicConfiguration.name - : '${name}${nicConfiguration.nicSuffix}' + networkInterfaceName: nicConfiguration.?name ?? '${name}${nicConfiguration.?nicSuffix}' virtualMachineName: name location: location - enableIPForwarding: contains(nicConfiguration, 'enableIPForwarding') ? nicConfiguration.enableIPForwarding : false - enableAcceleratedNetworking: contains(nicConfiguration, 'enableAcceleratedNetworking') - ? nicConfiguration.enableAcceleratedNetworking - : true + enableIPForwarding: nicConfiguration.?enableIPForwarding ?? false + enableAcceleratedNetworking: nicConfiguration.?enableAcceleratedNetworking ?? true dnsServers: contains(nicConfiguration, 'dnsServers') ? (!empty(nicConfiguration.dnsServers) ? nicConfiguration.dnsServers : []) : [] - networkSecurityGroupResourceId: contains(nicConfiguration, 'networkSecurityGroupResourceId') - ? nicConfiguration.networkSecurityGroupResourceId - : '' + networkSecurityGroupResourceId: nicConfiguration.?networkSecurityGroupResourceId ?? '' ipConfigurations: nicConfiguration.ipConfigurations lock: nicConfiguration.?lock ?? lock tags: nicConfiguration.?tags ?? tags @@ -503,7 +497,7 @@ module vm_nic 'modules/nic-configuration.bicep' = [ } ] -resource vm 'Microsoft.Compute/virtualMachines@2024-03-01' = { +resource vm 'Microsoft.Compute/virtualMachines@2024-07-01' = { name: name location: location identity: identity @@ -573,13 +567,13 @@ resource vm 'Microsoft.Compute/virtualMachines@2024-03-01' = { networkInterfaces: [ for (nicConfiguration, index) in nicConfigurations: { properties: { - deleteOption: contains(nicConfiguration, 'deleteOption') ? nicConfiguration.deleteOption : 'Delete' + deleteOption: nicConfiguration.?deleteOption ?? 'Delete' primary: index == 0 ? true : false } #disable-next-line use-resource-id-functions // It's a reference from inside a loop which makes resolving it using a resource reference particulary difficult. id: az.resourceId( 'Microsoft.Network/networkInterfaces', - contains(nicConfiguration, 'name') ? nicConfiguration.name : '${name}${nicConfiguration.nicSuffix}' + nicConfiguration.?name ?? '${name}${nicConfiguration.?nicSuffix}' ) } ] @@ -654,28 +648,20 @@ resource vm_autoShutdownConfiguration 'Microsoft.DevTestLab/schedules@2018-09-15 name: 'shutdown-computevm-${vm.name}' location: location properties: { - status: contains(autoShutdownConfig, 'status') ? autoShutdownConfig.status : 'Disabled' + status: autoShutdownConfig.?status ?? 'Disabled' targetResourceId: vm.id taskType: 'ComputeVmShutdownTask' dailyRecurrence: { - time: contains(autoShutdownConfig, 'dailyRecurrenceTime') ? autoShutdownConfig.dailyRecurrenceTime : '19:00' + time: autoShutdownConfig.?dailyRecurrenceTime ?? '19:00' } - timeZoneId: contains(autoShutdownConfig, 'timeZone') ? autoShutdownConfig.timeZone : 'UTC' + timeZoneId: autoShutdownConfig.?timeZone ?? 'UTC' notificationSettings: contains(autoShutdownConfig, 'notificationStatus') ? { - status: contains(autoShutdownConfig, 'notificationStatus') - ? autoShutdownConfig.notificationStatus - : 'Disabled' - emailRecipient: contains(autoShutdownConfig, 'notificationEmail') ? autoShutdownConfig.notificationEmail : '' - notificationLocale: contains(autoShutdownConfig, 'notificationLocale') - ? autoShutdownConfig.notificationLocale - : 'en' - webhookUrl: contains(autoShutdownConfig, 'notificationWebhookUrl') - ? autoShutdownConfig.notificationWebhookUrl - : '' - timeInMinutes: contains(autoShutdownConfig, 'notificationTimeInMinutes') - ? autoShutdownConfig.notificationTimeInMinutes - : 30 + status: autoShutdownConfig.?notificationStatus ?? 'Disabled' + emailRecipient: autoShutdownConfig.?notificationEmail ?? '' + notificationLocale: autoShutdownConfig.?notificationLocale ?? 'en' + webhookUrl: autoShutdownConfig.?notificationWebhookUrl ?? '' + timeInMinutes: autoShutdownConfig.?notificationTimeInMinutes ?? 30 } : null } @@ -689,16 +675,10 @@ module vm_aadJoinExtension 'extension/main.bicep' = if (extensionAadJoinConfig.e location: location publisher: 'Microsoft.Azure.ActiveDirectory' type: osType == 'Windows' ? 'AADLoginForWindows' : 'AADSSHLoginforLinux' - typeHandlerVersion: contains(extensionAadJoinConfig, 'typeHandlerVersion') - ? extensionAadJoinConfig.typeHandlerVersion - : (osType == 'Windows' ? '2.0' : '1.0') - autoUpgradeMinorVersion: contains(extensionAadJoinConfig, 'autoUpgradeMinorVersion') - ? extensionAadJoinConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionAadJoinConfig, 'enableAutomaticUpgrade') - ? extensionAadJoinConfig.enableAutomaticUpgrade - : false - settings: contains(extensionAadJoinConfig, 'settings') ? extensionAadJoinConfig.settings : {} + typeHandlerVersion: extensionAadJoinConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '2.0' : '1.0') + autoUpgradeMinorVersion: extensionAadJoinConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAadJoinConfig.?enableAutomaticUpgrade ?? false + settings: extensionAadJoinConfig.?settings ?? {} supressFailures: extensionAadJoinConfig.?supressFailures ?? false tags: extensionAadJoinConfig.?tags ?? tags } @@ -712,15 +692,9 @@ module vm_domainJoinExtension 'extension/main.bicep' = if (contains(extensionDom location: location publisher: 'Microsoft.Compute' type: 'JsonADDomainExtension' - typeHandlerVersion: contains(extensionDomainJoinConfig, 'typeHandlerVersion') - ? extensionDomainJoinConfig.typeHandlerVersion - : '1.3' - autoUpgradeMinorVersion: contains(extensionDomainJoinConfig, 'autoUpgradeMinorVersion') - ? extensionDomainJoinConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionDomainJoinConfig, 'enableAutomaticUpgrade') - ? extensionDomainJoinConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionDomainJoinConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionDomainJoinConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDomainJoinConfig.?enableAutomaticUpgrade ?? false settings: extensionDomainJoinConfig.settings supressFailures: extensionDomainJoinConfig.?supressFailures ?? false tags: extensionDomainJoinConfig.?tags ?? tags @@ -741,15 +715,9 @@ module vm_microsoftAntiMalwareExtension 'extension/main.bicep' = if (extensionAn location: location publisher: 'Microsoft.Azure.Security' type: 'IaaSAntimalware' - typeHandlerVersion: contains(extensionAntiMalwareConfig, 'typeHandlerVersion') - ? extensionAntiMalwareConfig.typeHandlerVersion - : '1.3' - autoUpgradeMinorVersion: contains(extensionAntiMalwareConfig, 'autoUpgradeMinorVersion') - ? extensionAntiMalwareConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionAntiMalwareConfig, 'enableAutomaticUpgrade') - ? extensionAntiMalwareConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionAntiMalwareConfig.?typeHandlerVersion ?? '1.3' + autoUpgradeMinorVersion: extensionAntiMalwareConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAntiMalwareConfig.?enableAutomaticUpgrade ?? false settings: extensionAntiMalwareConfig.settings supressFailures: extensionAntiMalwareConfig.?supressFailures ?? false tags: extensionAntiMalwareConfig.?tags ?? tags @@ -799,17 +767,11 @@ module vm_dependencyAgentExtension 'extension/main.bicep' = if (extensionDepende location: location publisher: 'Microsoft.Azure.Monitoring.DependencyAgent' type: osType == 'Windows' ? 'DependencyAgentWindows' : 'DependencyAgentLinux' - typeHandlerVersion: contains(extensionDependencyAgentConfig, 'typeHandlerVersion') - ? extensionDependencyAgentConfig.typeHandlerVersion - : '9.10' - autoUpgradeMinorVersion: contains(extensionDependencyAgentConfig, 'autoUpgradeMinorVersion') - ? extensionDependencyAgentConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionDependencyAgentConfig, 'enableAutomaticUpgrade') - ? extensionDependencyAgentConfig.enableAutomaticUpgrade - : true + typeHandlerVersion: extensionDependencyAgentConfig.?typeHandlerVersion ?? '9.10' + autoUpgradeMinorVersion: extensionDependencyAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDependencyAgentConfig.?enableAutomaticUpgrade ?? true settings: { - enableAMA: contains(extensionDependencyAgentConfig, 'enableAMA') ? extensionDependencyAgentConfig.enableAMA : true + enableAMA: extensionDependencyAgentConfig.?enableAMA ?? true } supressFailures: extensionDependencyAgentConfig.?supressFailures ?? false tags: extensionDependencyAgentConfig.?tags ?? tags @@ -827,15 +789,9 @@ module vm_networkWatcherAgentExtension 'extension/main.bicep' = if (extensionNet location: location publisher: 'Microsoft.Azure.NetworkWatcher' type: osType == 'Windows' ? 'NetworkWatcherAgentWindows' : 'NetworkWatcherAgentLinux' - typeHandlerVersion: contains(extensionNetworkWatcherAgentConfig, 'typeHandlerVersion') - ? extensionNetworkWatcherAgentConfig.typeHandlerVersion - : '1.4' - autoUpgradeMinorVersion: contains(extensionNetworkWatcherAgentConfig, 'autoUpgradeMinorVersion') - ? extensionNetworkWatcherAgentConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionNetworkWatcherAgentConfig, 'enableAutomaticUpgrade') - ? extensionNetworkWatcherAgentConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionNetworkWatcherAgentConfig.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNetworkWatcherAgentConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNetworkWatcherAgentConfig.?enableAutomaticUpgrade ?? false supressFailures: extensionNetworkWatcherAgentConfig.?supressFailures ?? false tags: extensionNetworkWatcherAgentConfig.?tags ?? tags } @@ -852,19 +808,13 @@ module vm_desiredStateConfigurationExtension 'extension/main.bicep' = if (extens location: location publisher: 'Microsoft.Powershell' type: 'DSC' - typeHandlerVersion: contains(extensionDSCConfig, 'typeHandlerVersion') - ? extensionDSCConfig.typeHandlerVersion - : '2.77' - autoUpgradeMinorVersion: contains(extensionDSCConfig, 'autoUpgradeMinorVersion') - ? extensionDSCConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionDSCConfig, 'enableAutomaticUpgrade') - ? extensionDSCConfig.enableAutomaticUpgrade - : false - settings: contains(extensionDSCConfig, 'settings') ? extensionDSCConfig.settings : {} + typeHandlerVersion: extensionDSCConfig.?typeHandlerVersion ?? '2.77' + autoUpgradeMinorVersion: extensionDSCConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionDSCConfig.?enableAutomaticUpgrade ?? false + settings: extensionDSCConfig.?settings ?? {} supressFailures: extensionDSCConfig.?supressFailures ?? false tags: extensionDSCConfig.?tags ?? tags - protectedSettings: contains(extensionDSCConfig, 'protectedSettings') ? extensionDSCConfig.protectedSettings : {} + protectedSettings: extensionDSCConfig.?protectedSettings ?? {} } dependsOn: [ vm_networkWatcherAgentExtension @@ -879,15 +829,9 @@ module vm_customScriptExtension 'extension/main.bicep' = if (extensionCustomScri location: location publisher: osType == 'Windows' ? 'Microsoft.Compute' : 'Microsoft.Azure.Extensions' type: osType == 'Windows' ? 'CustomScriptExtension' : 'CustomScript' - typeHandlerVersion: contains(extensionCustomScriptConfig, 'typeHandlerVersion') - ? extensionCustomScriptConfig.typeHandlerVersion - : (osType == 'Windows' ? '1.10' : '2.1') - autoUpgradeMinorVersion: contains(extensionCustomScriptConfig, 'autoUpgradeMinorVersion') - ? extensionCustomScriptConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionCustomScriptConfig, 'enableAutomaticUpgrade') - ? extensionCustomScriptConfig.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionCustomScriptConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '1.10' : '2.1') + autoUpgradeMinorVersion: extensionCustomScriptConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionCustomScriptConfig.?enableAutomaticUpgrade ?? false settings: { fileUris: [ for fileData in extensionCustomScriptConfig.fileData: contains(fileData, 'storageAccountId') @@ -912,18 +856,10 @@ module vm_azureDiskEncryptionExtension 'extension/main.bicep' = if (extensionAzu location: location publisher: 'Microsoft.Azure.Security' type: osType == 'Windows' ? 'AzureDiskEncryption' : 'AzureDiskEncryptionForLinux' - typeHandlerVersion: contains(extensionAzureDiskEncryptionConfig, 'typeHandlerVersion') - ? extensionAzureDiskEncryptionConfig.typeHandlerVersion - : (osType == 'Windows' ? '2.2' : '1.1') - autoUpgradeMinorVersion: contains(extensionAzureDiskEncryptionConfig, 'autoUpgradeMinorVersion') - ? extensionAzureDiskEncryptionConfig.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionAzureDiskEncryptionConfig, 'enableAutomaticUpgrade') - ? extensionAzureDiskEncryptionConfig.enableAutomaticUpgrade - : false - forceUpdateTag: contains(extensionAzureDiskEncryptionConfig, 'forceUpdateTag') - ? extensionAzureDiskEncryptionConfig.forceUpdateTag - : '1.0' + typeHandlerVersion: extensionAzureDiskEncryptionConfig.?typeHandlerVersion ?? (osType == 'Windows' ? '2.2' : '1.1') + autoUpgradeMinorVersion: extensionAzureDiskEncryptionConfig.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionAzureDiskEncryptionConfig.?enableAutomaticUpgrade ?? false + forceUpdateTag: extensionAzureDiskEncryptionConfig.?forceUpdateTag ?? '1.0' settings: extensionAzureDiskEncryptionConfig.?settings ?? {} supressFailures: extensionAzureDiskEncryptionConfig.?supressFailures ?? false tags: extensionAzureDiskEncryptionConfig.?tags ?? tags @@ -941,15 +877,9 @@ module vm_nvidiaGpuDriverWindowsExtension 'extension/main.bicep' = if (extension location: location publisher: 'Microsoft.HpcCompute' type: 'NvidiaGpuDriverWindows' - typeHandlerVersion: contains(extensionNvidiaGpuDriverWindows, 'typeHandlerVersion') - ? extensionNvidiaGpuDriverWindows.typeHandlerVersion - : '1.4' - autoUpgradeMinorVersion: contains(extensionNvidiaGpuDriverWindows, 'autoUpgradeMinorVersion') - ? extensionNvidiaGpuDriverWindows.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionNvidiaGpuDriverWindows, 'enableAutomaticUpgrade') - ? extensionNvidiaGpuDriverWindows.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionNvidiaGpuDriverWindows.?typeHandlerVersion ?? '1.4' + autoUpgradeMinorVersion: extensionNvidiaGpuDriverWindows.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionNvidiaGpuDriverWindows.?enableAutomaticUpgrade ?? false supressFailures: extensionNvidiaGpuDriverWindows.?supressFailures ?? false tags: extensionNvidiaGpuDriverWindows.?tags ?? tags } @@ -966,15 +896,9 @@ module vm_hostPoolRegistrationExtension 'extension/main.bicep' = if (extensionHo location: location publisher: 'Microsoft.PowerShell' type: 'DSC' - typeHandlerVersion: contains(extensionHostPoolRegistration, 'typeHandlerVersion') - ? extensionHostPoolRegistration.typeHandlerVersion - : '2.77' - autoUpgradeMinorVersion: contains(extensionHostPoolRegistration, 'autoUpgradeMinorVersion') - ? extensionHostPoolRegistration.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionHostPoolRegistration, 'enableAutomaticUpgrade') - ? extensionHostPoolRegistration.enableAutomaticUpgrade - : false + typeHandlerVersion: extensionHostPoolRegistration.?typeHandlerVersion ?? '2.77' + autoUpgradeMinorVersion: extensionHostPoolRegistration.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionHostPoolRegistration.?enableAutomaticUpgrade ?? false settings: { modulesUrl: extensionHostPoolRegistration.modulesUrl configurationFunction: extensionHostPoolRegistration.configurationFunction @@ -1000,21 +924,11 @@ module vm_azureGuestConfigurationExtension 'extension/main.bicep' = if (extensio location: location publisher: 'Microsoft.GuestConfiguration' type: osType == 'Windows' ? 'ConfigurationforWindows' : 'ConfigurationForLinux' - typeHandlerVersion: contains(extensionGuestConfigurationExtension, 'typeHandlerVersion') - ? extensionGuestConfigurationExtension.typeHandlerVersion - : (osType == 'Windows' ? '1.0' : '1.0') - autoUpgradeMinorVersion: contains(extensionGuestConfigurationExtension, 'autoUpgradeMinorVersion') - ? extensionGuestConfigurationExtension.autoUpgradeMinorVersion - : true - enableAutomaticUpgrade: contains(extensionGuestConfigurationExtension, 'enableAutomaticUpgrade') - ? extensionGuestConfigurationExtension.enableAutomaticUpgrade - : true - forceUpdateTag: contains(extensionGuestConfigurationExtension, 'forceUpdateTag') - ? extensionGuestConfigurationExtension.forceUpdateTag - : '1.0' - settings: contains(extensionGuestConfigurationExtension, 'settings') - ? extensionGuestConfigurationExtension.settings - : {} + typeHandlerVersion: extensionGuestConfigurationExtension.?typeHandlerVersion ?? (osType == 'Windows' ? '1.0' : '1.0') + autoUpgradeMinorVersion: extensionGuestConfigurationExtension.?autoUpgradeMinorVersion ?? true + enableAutomaticUpgrade: extensionGuestConfigurationExtension.?enableAutomaticUpgrade ?? true + forceUpdateTag: extensionGuestConfigurationExtension.?forceUpdateTag ?? '1.0' + settings: extensionGuestConfigurationExtension.?settings ?? {} supressFailures: extensionGuestConfigurationExtension.?supressFailures ?? false protectedSettings: extensionGuestConfigurationExtensionProtectedSettings tags: extensionGuestConfigurationExtension.?tags ?? tags diff --git a/avm/res/compute/virtual-machine/main.json b/avm/res/compute/virtual-machine/main.json index a92c91c855..de1432dd89 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.29.47.4906", - "templateHash": "17479703443253656975" + "version": "0.30.3.12046", + "templateHash": "1443306495474212036" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", @@ -975,7 +975,7 @@ }, "vm": { "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-03-01", + "apiVersion": "2024-07-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "identity": "[variables('identity')]", @@ -1047,10 +1047,10 @@ "count": "[length(parameters('nicConfigurations'))]", "input": { "properties": { - "deleteOption": "[if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].deleteOption, 'Delete')]", + "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', if(contains(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].name, format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex('networkInterfaces')].nicSuffix)))]" + "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" } } ] @@ -1110,14 +1110,14 @@ "name": "[format('shutdown-computevm-{0}', parameters('name'))]", "location": "[parameters('location')]", "properties": { - "status": "[if(contains(parameters('autoShutdownConfig'), 'status'), parameters('autoShutdownConfig').status, 'Disabled')]", + "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", "taskType": "ComputeVmShutdownTask", "dailyRecurrence": { - "time": "[if(contains(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), parameters('autoShutdownConfig').dailyRecurrenceTime, '19:00')]" + "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" }, - "timeZoneId": "[if(contains(parameters('autoShutdownConfig'), 'timeZone'), parameters('autoShutdownConfig').timeZone, 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), createObject('status', if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), parameters('autoShutdownConfig').notificationStatus, 'Disabled'), 'emailRecipient', if(contains(parameters('autoShutdownConfig'), 'notificationEmail'), parameters('autoShutdownConfig').notificationEmail, ''), 'notificationLocale', if(contains(parameters('autoShutdownConfig'), 'notificationLocale'), parameters('autoShutdownConfig').notificationLocale, 'en'), 'webhookUrl', if(contains(parameters('autoShutdownConfig'), 'notificationWebhookUrl'), parameters('autoShutdownConfig').notificationWebhookUrl, ''), 'timeInMinutes', if(contains(parameters('autoShutdownConfig'), 'notificationTimeInMinutes'), parameters('autoShutdownConfig').notificationTimeInMinutes, 30)), null())]" + "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", + "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationStatus'), 'Disabled'), 'emailRecipient', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationEmail'), ''), 'notificationLocale', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationWebhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationTimeInMinutes'), 30)), null())]" }, "dependsOn": [ "vm" @@ -1206,17 +1206,25 @@ }, "mode": "Incremental", "parameters": { - "networkInterfaceName": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'name'), createObject('value', parameters('nicConfigurations')[copyIndex()].name), createObject('value', format('{0}{1}', parameters('name'), parameters('nicConfigurations')[copyIndex()].nicSuffix)))]", + "networkInterfaceName": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" + }, "virtualMachineName": { "value": "[parameters('name')]" }, "location": { "value": "[parameters('location')]" }, - "enableIPForwarding": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableIPForwarding), createObject('value', false()))]", - "enableAcceleratedNetworking": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), createObject('value', parameters('nicConfigurations')[copyIndex()].enableAcceleratedNetworking), createObject('value', true()))]", + "enableIPForwarding": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" + }, + "enableAcceleratedNetworking": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" + }, "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), createObject('value', parameters('nicConfigurations')[copyIndex()].networkSecurityGroupResourceId), createObject('value', ''))]", + "networkSecurityGroupResourceId": { + "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" + }, "ipConfigurations": { "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" }, @@ -1243,8 +1251,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1517797599230349789" + "version": "0.30.3.12046", + "templateHash": "191716886366421622" } }, "definitions": { @@ -1533,7 +1541,7 @@ "name": "networkInterface_publicIPAddresses", "count": "[length(parameters('ipConfigurations'))]" }, - "condition": "[contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration')]", + "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), not(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressResourceId')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", @@ -1543,7 +1551,9 @@ }, "mode": "Incremental", "parameters": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'name'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.name), createObject('value', format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIpNameSuffix)))]", + "name": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIpNameSuffix')))]" + }, "diagnosticSettings": { "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" }, @@ -1562,16 +1572,30 @@ "dnsSettings": { "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" }, - "publicIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAddressVersion), createObject('value', 'IPv4'))]", - "publicIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPAllocationMethod), createObject('value', 'Static'))]", - "publicIpPrefixResourceId": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.publicIPPrefixResourceId), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.roleAssignments), createObject('value', createArray()))]", - "skuName": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuName), createObject('value', 'Standard'))]", - "skuTier": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.skuTier), createObject('value', 'Regional'))]", + "publicIPAddressVersion": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), 'IPv4')]" + }, + "publicIPAllocationMethod": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), 'Static')]" + }, + "publicIpPrefixResourceId": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), '')]" + }, + "roleAssignments": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createArray())]" + }, + "skuName": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), 'Standard')]" + }, + "skuTier": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), 'Regional')]" + }, "tags": { "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" }, - "zones": "[if(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createObject('value', parameters('ipConfigurations')[copyIndex()].pipConfiguration.zones), createObject('value', createArray(1, 2, 3)))]", + "zones": { + "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createArray(1, 2, 3))]" + }, "enableTelemetry": { "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" } @@ -1583,8 +1607,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.27.1.19265", - "templateHash": "10356333973104369631" + "version": "0.29.47.4906", + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1596,6 +1620,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -2009,6 +2040,13 @@ } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", @@ -2019,15 +2057,15 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2081,20 +2119,20 @@ "publicIpAddress_roleAssignments": { "copy": { "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "publicIpAddress" @@ -2200,7 +2238,7 @@ { "name": "value", "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), resourceId('Microsoft.Network/publicIPAddresses', if(contains(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'name'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.name, format('{0}{1}', parameters('virtualMachineName'), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIpNameSuffix))), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerBackendAddressPools, null()), 'applicationSecurityGroups', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('value')].applicationSecurityGroups, null()), 'applicationGatewayBackendAddressPools', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('value')].applicationGatewayBackendAddressPools, null()), 'gatewayLoadBalancer', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('value')].gatewayLoadBalancer, null()), 'loadBalancerInboundNatRules', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('value')].loadBalancerInboundNatRules, null()), 'privateIPAddressVersion', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('value')].privateIPAddressVersion, null()), 'virtualNetworkTaps', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('value')].virtualNetworkTaps, null()))]" + "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), if(not(contains(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'publicIpNameSuffix')))), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIPAddressResourceId), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), null()), 'applicationSecurityGroups', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), null()), 'applicationGatewayBackendAddressPools', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), null()), 'gatewayLoadBalancer', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), null()), 'loadBalancerInboundNatRules', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), null()), 'privateIPAddressVersion', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), null()), 'virtualNetworkTaps', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), null()))]" } ] }, @@ -2236,8 +2274,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "1612343535299711142" + "version": "0.29.47.4906", + "templateHash": "9226998037927576702" }, "name": "Network Interface", "description": "This module deploys a Network Interface.", @@ -2369,6 +2407,13 @@ "items": { "type": "object", "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, "roleDefinitionIdOrName": { "type": "string", "metadata": { @@ -2571,6 +2616,13 @@ } }, "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", @@ -2579,15 +2631,15 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { "avmTelemetry": { "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.2.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2693,20 +2745,20 @@ "networkInterface_roleAssignments": { "copy": { "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "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')]" + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ "networkInterface" @@ -2777,10 +2829,18 @@ "value": "Microsoft.Azure.ActiveDirectory" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAadJoinConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAadJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAadJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionAadJoinConfig'), 'settings'), createObject('value', parameters('extensionAadJoinConfig').settings), createObject('value', createObject()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]" + }, "supressFailures": { "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" }, @@ -2795,8 +2855,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -2979,9 +3039,15 @@ "type": { "value": "JsonADDomainExtension" }, - "typeHandlerVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDomainJoinConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDomainJoinConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDomainJoinConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" + }, "settings": { "value": "[parameters('extensionDomainJoinConfig').settings]" }, @@ -3004,8 +3070,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3189,9 +3255,15 @@ "type": { "value": "IaaSAntimalware" }, - "typeHandlerVersion": "[if(contains(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAntiMalwareConfig').typeHandlerVersion), createObject('value', '1.3'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAntiMalwareConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAntiMalwareConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" + }, "settings": { "value": "[parameters('extensionAntiMalwareConfig').settings]" }, @@ -3209,8 +3281,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3415,8 +3487,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3598,12 +3670,18 @@ "value": "Microsoft.Azure.Monitoring.DependencyAgent" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDependencyAgentConfig').typeHandlerVersion), createObject('value', '9.10'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDependencyAgentConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDependencyAgentConfig').enableAutomaticUpgrade), createObject('value', true()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" + }, "settings": { "value": { - "enableAMA": "[if(contains(parameters('extensionDependencyAgentConfig'), 'enableAMA'), parameters('extensionDependencyAgentConfig').enableAMA, true())]" + "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" } }, "supressFailures": { @@ -3620,8 +3698,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3803,9 +3881,15 @@ "value": "Microsoft.Azure.NetworkWatcher" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNetworkWatcherAgentConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" + }, "supressFailures": { "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" }, @@ -3820,8 +3904,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4005,17 +4089,27 @@ "type": { "value": "DSC" }, - "typeHandlerVersion": "[if(contains(parameters('extensionDSCConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionDSCConfig').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionDSCConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionDSCConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "settings": "[if(contains(parameters('extensionDSCConfig'), 'settings'), createObject('value', parameters('extensionDSCConfig').settings), createObject('value', createObject()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" + }, "supressFailures": { "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" }, "tags": { "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" }, - "protectedSettings": "[if(contains(parameters('extensionDSCConfig'), 'protectedSettings'), createObject('value', parameters('extensionDSCConfig').protectedSettings), createObject('value', createObject()))]" + "protectedSettings": { + "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -4024,8 +4118,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4205,9 +4299,15 @@ }, "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionCustomScriptConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.10'), createObject('value', '2.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionCustomScriptConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionCustomScriptConfig').enableAutomaticUpgrade), createObject('value', false()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" + }, "settings": { "value": { "copy": [ @@ -4236,8 +4336,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4419,10 +4519,18 @@ "value": "Microsoft.Azure.Security" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '2.2'), createObject('value', '1.1')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').enableAutomaticUpgrade), createObject('value', false()))]", - "forceUpdateTag": "[if(contains(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), createObject('value', parameters('extensionAzureDiskEncryptionConfig').forceUpdateTag), createObject('value', '1.0'))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" + }, "settings": { "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" }, @@ -4440,8 +4548,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4625,9 +4733,15 @@ "type": { "value": "NvidiaGpuDriverWindows" }, - "typeHandlerVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').typeHandlerVersion), createObject('value', '1.4'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionNvidiaGpuDriverWindows').enableAutomaticUpgrade), createObject('value', false()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" + }, "supressFailures": { "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" }, @@ -4642,8 +4756,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4827,9 +4941,15 @@ "type": { "value": "DSC" }, - "typeHandlerVersion": "[if(contains(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), createObject('value', parameters('extensionHostPoolRegistration').typeHandlerVersion), createObject('value', '2.77'))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionHostPoolRegistration').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionHostPoolRegistration').enableAutomaticUpgrade), createObject('value', false()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" + }, "settings": { "value": { "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", @@ -4853,8 +4973,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5034,11 +5154,21 @@ "value": "Microsoft.GuestConfiguration" }, "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), createObject('value', parameters('extensionGuestConfigurationExtension').typeHandlerVersion), if(equals(parameters('osType'), 'Windows'), createObject('value', '1.0'), createObject('value', '1.0')))]", - "autoUpgradeMinorVersion": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), createObject('value', parameters('extensionGuestConfigurationExtension').autoUpgradeMinorVersion), createObject('value', true()))]", - "enableAutomaticUpgrade": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionGuestConfigurationExtension').enableAutomaticUpgrade), createObject('value', true()))]", - "forceUpdateTag": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), createObject('value', parameters('extensionGuestConfigurationExtension').forceUpdateTag), createObject('value', '1.0'))]", - "settings": "[if(contains(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject('value', parameters('extensionGuestConfigurationExtension').settings), createObject('value', createObject()))]", + "typeHandlerVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" + }, + "autoUpgradeMinorVersion": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" + }, + "enableAutomaticUpgrade": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" + }, + "forceUpdateTag": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" + }, + "settings": { + "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" + }, "supressFailures": { "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" }, @@ -5056,8 +5186,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10657605324993327332" + "version": "0.30.3.12046", + "templateHash": "1742015474710386242" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -5255,8 +5385,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4676289166883418684" + "version": "0.30.3.12046", + "templateHash": "18427642917647797213" }, "name": "Recovery Service Vaults Protection Container Protected Item", "description": "This module deploys a Recovery Services Vault Protection Container Protected Item.", @@ -5390,14 +5520,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('vm', '2024-03-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('vm', '2024-03-01', 'full').location]" + "value": "[reference('vm', '2024-07-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/compute/virtual-machine/modules/nic-configuration.bicep b/avm/res/compute/virtual-machine/modules/nic-configuration.bicep index 19f46b427f..9c6bad7362 100644 --- a/avm/res/compute/virtual-machine/modules/nic-configuration.bicep +++ b/avm/res/compute/virtual-machine/modules/nic-configuration.bicep @@ -27,51 +27,38 @@ param diagnosticSettings diagnosticSettingType @description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType -module networkInterface_publicIPAddresses 'br/public:avm/res/network/public-ip-address:0.4.1' = [ - for (ipConfiguration, index) in ipConfigurations: if (contains(ipConfiguration, 'pipConfiguration')) { +module networkInterface_publicIPAddresses 'br/public:avm/res/network/public-ip-address:0.6.0' = [ + for (ipConfiguration, index) in ipConfigurations: if (contains(ipConfiguration, 'pipConfiguration') && !contains( + ipConfiguration.pipConfiguration, + 'publicIPAddressResourceId' + )) { name: '${deployment().name}-publicIP-${index}' params: { - name: contains(ipConfiguration.pipConfiguration, 'name') - ? ipConfiguration.pipConfiguration.name - : '${virtualMachineName}${ipConfiguration.pipConfiguration.publicIpNameSuffix}' + name: ipConfiguration.pipConfiguration.?name ?? '${virtualMachineName}${ipConfiguration.pipConfiguration.?publicIpNameSuffix}' diagnosticSettings: ipConfiguration.?diagnosticSettings location: location lock: lock idleTimeoutInMinutes: ipConfiguration.pipConfiguration.?idleTimeoutInMinutes ddosSettings: ipConfiguration.pipConfiguration.?ddosSettings dnsSettings: ipConfiguration.pipConfiguration.?dnsSettings - publicIPAddressVersion: contains(ipConfiguration.pipConfiguration, 'publicIPAddressVersion') - ? ipConfiguration.pipConfiguration.publicIPAddressVersion - : 'IPv4' - publicIPAllocationMethod: contains(ipConfiguration.pipConfiguration, 'publicIPAllocationMethod') - ? ipConfiguration.pipConfiguration.publicIPAllocationMethod - : 'Static' - publicIpPrefixResourceId: contains(ipConfiguration.pipConfiguration, 'publicIPPrefixResourceId') - ? ipConfiguration.pipConfiguration.publicIPPrefixResourceId - : '' - roleAssignments: contains(ipConfiguration.pipConfiguration, 'roleAssignments') - ? ipConfiguration.pipConfiguration.roleAssignments - : [] - skuName: contains(ipConfiguration.pipConfiguration, 'skuName') - ? ipConfiguration.pipConfiguration.skuName - : 'Standard' - skuTier: contains(ipConfiguration.pipConfiguration, 'skuTier') - ? ipConfiguration.pipConfiguration.skuTier - : 'Regional' + publicIPAddressVersion: ipConfiguration.pipConfiguration.?publicIPAddressVersion ?? 'IPv4' + publicIPAllocationMethod: ipConfiguration.pipConfiguration.?publicIPAllocationMethod ?? 'Static' + publicIpPrefixResourceId: ipConfiguration.pipConfiguration.?publicIPPrefixResourceId ?? '' + roleAssignments: ipConfiguration.pipConfiguration.?roleAssignments ?? [] + skuName: ipConfiguration.pipConfiguration.?skuName ?? 'Standard' + skuTier: ipConfiguration.pipConfiguration.?skuTier ?? 'Regional' tags: ipConfiguration.?tags ?? tags - zones: contains(ipConfiguration.pipConfiguration, 'zones') - ? ipConfiguration.pipConfiguration.zones - : [ - 1 - 2 - 3 - ] + zones: ipConfiguration.pipConfiguration.?zones ?? [ + 1 + 2 + 3 + ] enableTelemetry: ipConfiguration.?enableTelemetry ?? enableTelemetry } } ] -module networkInterface 'br/public:avm/res/network/network-interface:0.2.4' = { +module networkInterface 'br/public:avm/res/network/network-interface:0.4.0' = { name: '${deployment().name}-NetworkInterface' params: { name: networkInterfaceName @@ -86,33 +73,21 @@ module networkInterface 'br/public:avm/res/network/network-interface:0.2.4' = { ? (!empty(ipConfiguration.privateIPAddress) ? ipConfiguration.privateIPAddress : null) : null publicIPAddressResourceId: contains(ipConfiguration, 'pipConfiguration') - ? resourceId( - 'Microsoft.Network/publicIPAddresses', - contains(ipConfiguration.pipConfiguration, 'name') - ? ipConfiguration.pipConfiguration.name - : '${virtualMachineName}${ipConfiguration.pipConfiguration.publicIpNameSuffix}' - ) + ? !contains(ipConfiguration.pipConfiguration, 'publicIPAddressResourceId') + ? resourceId( + 'Microsoft.Network/publicIPAddresses', + ipConfiguration.pipConfiguration.?name ?? '${virtualMachineName}${ipConfiguration.pipConfiguration.?publicIpNameSuffix}' + ) + : ipConfiguration.pipConfiguration.publicIPAddressResourceId : null subnetResourceId: ipConfiguration.subnetResourceId - loadBalancerBackendAddressPools: contains(ipConfiguration, 'loadBalancerBackendAddressPools') - ? ipConfiguration.loadBalancerBackendAddressPools - : null - applicationSecurityGroups: contains(ipConfiguration, 'applicationSecurityGroups') - ? ipConfiguration.applicationSecurityGroups - : null - applicationGatewayBackendAddressPools: contains(ipConfiguration, 'applicationGatewayBackendAddressPools') - ? ipConfiguration.applicationGatewayBackendAddressPools - : null - gatewayLoadBalancer: contains(ipConfiguration, 'gatewayLoadBalancer') - ? ipConfiguration.gatewayLoadBalancer - : null - loadBalancerInboundNatRules: contains(ipConfiguration, 'loadBalancerInboundNatRules') - ? ipConfiguration.loadBalancerInboundNatRules - : null - privateIPAddressVersion: contains(ipConfiguration, 'privateIPAddressVersion') - ? ipConfiguration.privateIPAddressVersion - : null - virtualNetworkTaps: contains(ipConfiguration, 'virtualNetworkTaps') ? ipConfiguration.virtualNetworkTaps : null + loadBalancerBackendAddressPools: ipConfiguration.?loadBalancerBackendAddressPools ?? null + applicationSecurityGroups: ipConfiguration.?applicationSecurityGroups ?? null + applicationGatewayBackendAddressPools: ipConfiguration.?applicationGatewayBackendAddressPools ?? null + gatewayLoadBalancer: ipConfiguration.?gatewayLoadBalancer ?? null + loadBalancerInboundNatRules: ipConfiguration.?loadBalancerInboundNatRules ?? null + privateIPAddressVersion: ipConfiguration.?privateIPAddressVersion ?? null + virtualNetworkTaps: ipConfiguration.?virtualNetworkTaps ?? null } ] location: location diff --git a/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep index 32e5a29dec..fcfd8d428d 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/atmg/main.test.bicep @@ -1,3 +1,4 @@ +// WARNING: this test is disabled, as there is an known issue on Azure, preventing deployment, see https://techcommunity.microsoft.com/t5/azure-infrastructure/enabling-azure-automanage-or-creating-a-custom-configuration/m-p/4251861 targetScope = 'subscription' metadata name = 'Using automanage for the VM.' @@ -11,8 +12,9 @@ metadata description = 'This instance deploys the module with registering to an @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmlinatmg' @@ -20,10 +22,6 @@ param serviceShort string = 'cvmlinatmg' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -// Set to fixed location as the RP function returns unsupported locations (configurationProfileAssignments) -// Right now (2024/04) the following locations are supported: centralus, eastus, eastus2, southcentralus, westus, westus2, westcentralus, northeurope, westeurope, canadacentral, japaneast, uksouth, australiasoutheast, australiaeast, southeastasia, westus3 -param enforcedLocation string = 'westeurope' - // ============ // // Dependencies // // ============ // @@ -32,7 +30,7 @@ param enforcedLocation string = 'westeurope' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { @@ -58,7 +56,7 @@ module nestedDependencies 'dependencies.bicep' = { @batchSize(1) module testDeployment '../../../main.bicep' = [ - for iteration in ['init', 'idem']: { + for iteration in ['init', 'idem']: if (false) { scope: resourceGroup name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { @@ -98,7 +96,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' configurationProfile: '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction' disablePasswordAuthentication: true publicKeys: [ diff --git a/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep index f0d5ccaa71..16959ce774 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/linux.defaults/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmlinmin' @@ -28,14 +29,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' sshDeploymentScriptName: 'dep-${namePrefix}-ds-${serviceShort}' @@ -56,9 +57,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -90,7 +91,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' disablePasswordAuthentication: true publicKeys: [ { diff --git a/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep index b0b2b53a5a..f19060fba7 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/linux.max/dependencies.bicep @@ -34,7 +34,7 @@ param dcrName string @description('Optional. The location to deploy to.') param location string = resourceGroup().location -@description('Required. The object ID of the Backup Management Service Enterprise Application. Required for Customer-Managed-Keys.') +@description('Required. The object ID of the Backup Management Service Enterprise Application.') param backupManagementServiceApplicationObjectId string @description('Required. Resource ID of the log analytics worspace to stream logs from Azure monitoring agent.') diff --git a/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep index 6b1d1a4e1e..cd05048ddb 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/linux.max/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmlinmax' @@ -32,14 +33,14 @@ param backupManagementServiceEnterpriseApplicationObjectId string = '' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' @@ -60,13 +61,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -76,11 +77,11 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}' params: { name: '${namePrefix}${serviceShort}' computerName: '${namePrefix}linvm1' - location: resourceLocation + location: enforcedLocation adminUsername: 'localAdministrator' imageReference: { publisher: 'Canonical' @@ -199,7 +200,7 @@ module testDeployment '../../../main.bicep' = { } } osType: 'Linux' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' zone: 1 backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName backupVaultName: nestedDependencies.outputs.recoveryServicesVaultName diff --git a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep index 795ab9dfa7..15da56837a 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/dependencies.bicep @@ -31,7 +31,7 @@ param proximityPlacementGroupName string @description('Optional. The location to deploy resources to.') param location string = resourceGroup().location -@description('Required. The object ID of the Backup Management Service Enterprise Application. Required for Customer-Managed-Keys.') +@description('Required. The object ID of the Backup Management Service Enterprise Application.') param backupManagementServiceApplicationObjectId string @description('Required. The name of the data collection rule.') diff --git a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep index fd619b1589..45ba5ad582 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/waf-aligned/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinwaf' @@ -36,14 +37,14 @@ param backupManagementServiceEnterpriseApplicationObjectId string = '' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' maintenanceConfigurationName: 'dep-${namePrefix}-mc-${serviceShort}' applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' @@ -64,13 +65,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -82,9 +83,9 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' computerName: '${namePrefix}winvm1' adminUsername: 'VMAdmin' @@ -176,7 +177,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password zone: 2 backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep index 7232384320..db778bf326 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.defaults/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinmin' @@ -32,14 +33,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' } } @@ -51,9 +52,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -82,7 +83,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password } } diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep index 0db2535978..e719018cf5 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.guestconfiguration/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the a guest config @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinguest' @@ -32,14 +33,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' } } @@ -51,12 +52,12 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { managedIdentities: { systemAssigned: true } - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -72,6 +73,10 @@ module testDeployment '../../../main.bicep' = [ { name: 'ipconfig01' subnetResourceId: nestedDependencies.outputs.subnetResourceId + pipConfiguration: { + publicIpNameSuffix: '-pip-01' + zones: [] + } } ] nicSuffix: '-nic-01' @@ -85,7 +90,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password extensionGuestConfigurationExtension: { enabled: true diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep index e13b61d4e3..06cb5b6633 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.hostpool/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module and registers it in a h @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinhp' @@ -24,10 +25,6 @@ param password string = newGuid() @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -// Set to fixed location as the RP function returns unsupported locations -// Right now (2024/04) the following locations are supported: centralindia,uksouth,ukwest,japaneast,australiaeast,canadaeast,canadacentral,northeurope,westeurope,eastus,eastus2,westus,westus2,westus3,northcentralus,southcentralus,westcentralus,centralus -param enforcedLocation string = 'westeurope' - // ============ // // Dependencies // // ============ // @@ -36,7 +33,7 @@ param enforcedLocation string = 'westeurope' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { @@ -58,7 +55,7 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { location: enforcedLocation name: '${namePrefix}${serviceShort}' @@ -92,7 +89,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password extensionAadJoinConfig: { enabled: true diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep index a492ad2a5a..bccba3d29d 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.max/dependencies.bicep @@ -10,6 +10,9 @@ param managedIdentityName string @description('Required. The name of the Load Balancer to create.') param loadBalancerName string +@description('Required. The name of the Public IP address to create.') +param publicIPAddressName string + @description('Required. The name of the Recovery Services Vault to create.') param recoveryServicesVaultName string @@ -28,7 +31,7 @@ param proximityPlacementGroupName string @description('Optional. The location to deploy resources to.') param location string = resourceGroup().location -@description('Required. The object ID of the Backup Management Service Enterprise Application. Required for Customer-Managed-Keys.') +@description('Required. The object ID of the Backup Management Service Enterprise Application.') param backupManagementServiceApplicationObjectId string @description('Required. The name of the data collection rule.') @@ -108,6 +111,17 @@ resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { } } +resource pip 'Microsoft.Network/publicIPAddresses@2024-01-01' = { + name: publicIPAddressName + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + resource recoveryServicesVault 'Microsoft.RecoveryServices/vaults@2022-04-01' = { name: recoveryServicesVaultName location: location @@ -404,6 +418,9 @@ output recoveryServicesVaultResourceGroupName string = resourceGroup().name @description('The name of the Backup Policy created in the Backup Recovery Vault.') output recoveryServicesVaultBackupPolicyName string = recoveryServicesVault::backupPolicy.name +@description('The resource ID of the created PIP.') +output publicIPAddressResourceId string = pip.id + @description('The resource ID of the created Key Vault.') output keyVaultResourceId string = keyVault.id diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep index ac79b215ce..96c3d990e2 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.max/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with most of its featur @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinmax' @@ -36,17 +37,18 @@ param backupManagementServiceEnterpriseApplicationObjectId string = '' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' applicationSecurityGroupName: 'dep-${namePrefix}-asg-${serviceShort}' managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + publicIPAddressName: 'dep-${namePrefix}-pip-${serviceShort}' keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' recoveryServicesVaultName: 'dep-${namePrefix}-rsv-${serviceShort}' @@ -63,13 +65,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: resourceLocation + location: enforcedLocation } } @@ -81,9 +83,9 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' computerName: '${namePrefix}winvm1' adminUsername: 'VMAdmin' @@ -110,12 +112,7 @@ module testDeployment '../../../main.bicep' = [ ] name: 'ipconfig01' pipConfiguration: { - publicIpNameSuffix: '-pip-01' - zones: [ - 1 - 2 - 3 - ] + publicIPAddressResourceId: nestedDependencies.outputs.publicIPAddressResourceId roleAssignments: [ { name: 'e962e7c1-261a-4afd-b5ad-17a640a0b7bc' @@ -205,7 +202,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password zone: 2 backupPolicyName: nestedDependencies.outputs.recoveryServicesVaultBackupPolicyName diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep index 035c2446ed..0b8df1ac01 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.nvidia/main.test.bicep @@ -11,6 +11,10 @@ metadata description = 'This instance deploys the module for a VM with dedicated @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinnv' @@ -21,9 +25,6 @@ param password string = newGuid() @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' -#disable-next-line no-hardcoded-location // Due to quotas and capacity challenges, this region must be used in the AVM testing subscription -var enforcedLocation = 'eastus' - // ============ // // Dependencies // // ============ // diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep index e3edaf2352..8c9e1a248c 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.ssecmk/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with disk enryption set @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwincmk' @@ -35,14 +36,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) keyVaultName: 'dep${namePrefix}kv${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' @@ -57,9 +58,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'VMAdministrator' imageReference: { @@ -90,7 +91,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password dataDisks: [ { diff --git a/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep index 55485d9ede..aa14a3502f 100644 --- a/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep +++ b/avm/res/compute/virtual-machine/tests/e2e/windows.vmss/main.test.bicep @@ -11,8 +11,9 @@ metadata description = 'This instance deploys the module with the minimum set of @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-compute.virtualMachines-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +// Capacity constraints for VM type +#disable-next-line no-hardcoded-location +var enforcedLocation = '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 = 'cvmwinvmss' @@ -32,14 +33,14 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' params: { - location: resourceLocation + location: enforcedLocation virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' vmssName: 'dep-${namePrefix}-vmss-${serviceShort}' pipName: 'dep-${namePrefix}-pip-${serviceShort}' @@ -54,9 +55,9 @@ module nestedDependencies 'dependencies.bicep' = { module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' params: { - location: resourceLocation + location: enforcedLocation name: '${namePrefix}${serviceShort}' adminUsername: 'localAdminUser' imageReference: { @@ -85,7 +86,7 @@ module testDeployment '../../../main.bicep' = [ } } osType: 'Windows' - vmSize: 'Standard_DS2_v2' + vmSize: 'Standard_D2s_v3' adminPassword: password virtualMachineScaleSetResourceId: nestedDependencies.outputs.vmssResourceId } diff --git a/avm/res/compute/virtual-machine/version.json b/avm/res/compute/virtual-machine/version.json index 09c3664cec..9a9a06e897 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.7", + "version": "0.8", "pathFilters": [ "./main.json" ] diff --git a/avm/res/consumption/budget/README.md b/avm/res/consumption/budget/README.md index 53638a6f17..a72051517a 100644 --- a/avm/res/consumption/budget/README.md +++ b/avm/res/consumption/budget/README.md @@ -59,7 +59,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,26 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbmin001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +``` + +
    +

    + ### Example 2: _Using `thresholdType` `Forecasted`_ This instance deploys the module with the minimum set of required parameters and `thresholdType` `Forecasted`. @@ -120,7 +140,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -153,6 +173,27 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbfcst001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +param thresholdType = 'Forecasted' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -194,7 +235,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -239,6 +280,37 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbmax001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +param resourceGroupFilter = [ + 'rg-group1' + 'rg-group2' +] +param thresholds = [ + 50 + 75 + 90 + 100 + 110 +] +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -276,7 +348,7 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -315,6 +387,33 @@ module budget 'br/public:avm/res/consumption/budget:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/consumption/budget:' + +// Required parameters +param amount = 500 +param name = 'cbwaf001' +// Non-required parameters +param contactEmails = [ + 'dummy@contoso.com' +] +param location = '' +param thresholds = [ + 50 + 75 + 90 + 100 + 110 +] +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/container-instance/container-group/README.md b/avm/res/container-instance/container-group/README.md index e34bffb713..e73e13b51e 100644 --- a/avm/res/container-instance/container-group/README.md +++ b/avm/res/container-instance/container-group/README.md @@ -83,7 +83,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -135,6 +135,48 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using CMK _ This instance deploys the module with a customer-managed key (CMK). @@ -232,7 +274,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -335,6 +377,93 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -441,7 +570,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -553,6 +682,102 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [ + { + name: 'CLIENT_ID' + value: 'TestClientId' + } + { + name: 'CLIENT_SECRET' + secureValue: 'TestSecret' + } + ] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _Using private network_ This instance deploys the module within a virtual network. @@ -645,7 +870,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -743,6 +968,88 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 4 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + { + port: 8080 + protocol: 'Tcp' + } +] +param name = 'cicgprivate001' +// Non-required parameters +param ipAddressType = 'Private' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param subnetId = '' +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -834,7 +1141,7 @@ module containerGroup 'br/public:avm/res/container-instance/container-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -929,6 +1236,87 @@ module containerGroup 'br/public:avm/res/container-instance/container-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-instance/container-group:' + +// Required parameters +param containers = [ + { + name: 'az-aci-x-001' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } + { + name: 'az-aci-x-002' + properties: { + command: [] + environmentVariables: [] + image: 'mcr.microsoft.com/azuredocs/aci-helloworld' + ports: [ + { + port: 8080 + protocol: 'Tcp' + } + ] + resources: { + requests: { + cpu: 2 + memoryInGB: 2 + } + } + } + } +] +param ipAddressPorts = [ + { + port: 80 + protocol: 'Tcp' + } + { + port: 443 + protocol: 'Tcp' + } +] +param name = 'cicgwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/container-registry/registry/README.md b/avm/res/container-registry/registry/README.md index f81a37d43a..eb764f51d8 100644 --- a/avm/res/container-registry/registry/README.md +++ b/avm/res/container-registry/registry/README.md @@ -94,7 +94,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -150,6 +150,48 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = '' +// Non-required parameters +param acrAdminUserEnabled = false +param acrSku = 'Standard' +param cacheRules = [ + { + credentialSetResourceId: '' + name: 'customRule' + sourceRepository: 'docker.io/library/hello-world' + targetRepository: 'cached-docker-hub/hello-world' + } +] +param credentialSets = [ + { + authCredentials: [ + { + name: 'Credential1' + passwordSecretIdentifier: '' + usernameSecretIdentifier: '' + } + ] + loginServer: 'docker.io' + managedIdentities: { + systemAssigned: true + } + name: 'default' + } +] +param location = '' +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -177,7 +219,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -202,6 +244,23 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrmin001' +// Non-required parameters +param acrSku = 'Standard' +param location = '' +``` + +
    +

    + ### Example 3: _Using encryption with Customer-Managed-Key_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -240,7 +299,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -282,6 +341,34 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrencr001' +// Non-required parameters +param acrSku = 'Premium' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param publicNetworkAccess = 'Disabled' +``` + +
    +

    + ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -409,7 +496,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -566,6 +653,123 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrmax001' +// Non-required parameters +param acrAdminUserEnabled = false +param acrSku = 'Premium' +param azureADAuthenticationAsArmPolicyStatus = 'enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param exportPolicyStatus = 'enabled' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param networkRuleSetIpRules = [ + { + action: 'Allow' + value: '40.74.28.0/23' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param quarantinePolicyStatus = 'enabled' +param replications = [ + { + location: '' + name: '' + } +] +param roleAssignments = [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param softDeletePolicyDays = 7 +param softDeletePolicyStatus = 'disabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param trustPolicyStatus = 'enabled' +param webhooks = [ + { + name: 'acrx001webhook' + serviceUri: 'https://www.contoso.com/webhook' + } +] +``` + +
    +

    + ### Example 5: _Using `scopeMaps` in parameter set_ This instance deploys the module with the scopeMaps feature. @@ -602,7 +806,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -638,6 +842,32 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrs001' +// Non-required parameters +param acrSku = 'Standard' +param location = '' +param scopeMaps = [ + { + actions: [ + 'repositories/*/content/read' + ] + description: 'This is a test for scopeMaps feature.' + name: 'testscopemap' + } +] +``` + +
    +

    + ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -703,7 +933,7 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -788,6 +1018,61 @@ module registry 'br/public:avm/res/container-registry/registry:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-registry/registry:' + +// Required parameters +param name = 'crrwaf001' +// Non-required parameters +param acrAdminUserEnabled = false +param acrSku = 'Premium' +param azureADAuthenticationAsArmPolicyStatus = 'enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param exportPolicyStatus = 'enabled' +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param quarantinePolicyStatus = 'enabled' +param replications = [ + { + location: '' + name: '' + } +] +param softDeletePolicyDays = 7 +param softDeletePolicyStatus = 'disabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param trustPolicyStatus = 'enabled' +``` + +
    +

    + ## Parameters **Required parameters** @@ -1526,6 +1811,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1696,6 +1992,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'AcrDelete'` + - `'AcrImageSigner'` + - `'AcrPull'` + - `'AcrPush'` + - `'AcrQuarantineReader'` + - `'AcrQuarantineWriter'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index 44a7b26a1e..3b68c8346d 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -93,7 +93,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -149,6 +149,50 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csauto001' +param primaryAgentPoolProfile = [ + { + count: 3 + mode: 'System' + name: 'systempool' + vmSize: 'Standard_DS2_v2' + } +] +// Non-required parameters +param location = '' +param maintenanceConfiguration = { + maintenanceWindow: { + durationHours: 4 + schedule: { + absoluteMonthly: '' + daily: '' + relativeMonthly: '' + weekly: { + dayOfWeek: 'Sunday' + intervalWeeks: 1 + } + } + startDate: '2024-07-03' + startTime: '00:00' + utcOffset: '+00:00' + } +} +param managedIdentities = { + systemAssigned: true +} +``` + +
    +

    + ### Example 2: _Using Azure CNI Network Plugin._ This instance deploys the module with Azure CNI network plugin . @@ -375,7 +419,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -653,6 +697,222 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmaz001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 1 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + proximityPlacementGroupResourceId: '' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +param autoUpgradeProfileUpgradeChannel = 'stable' +param customerManagedKey = { + keyName: '' + keyVaultNetworkAccess: 'Public' + keyVaultResourceId: '' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param diskEncryptionSetResourceId = '' +param enableAzureDefender = true +param enableAzureMonitorProfileMetrics = true +param enableKeyvaultSecretsProvider = true +param enableOidcIssuerProfile = true +param enablePodSecurityPolicy = false +param enableStorageProfileBlobCSIDriver = true +param enableStorageProfileDiskCSIDriver = true +param enableStorageProfileFileCSIDriver = true +param enableStorageProfileSnapshotController = true +param enableWorkloadIdentity = true +param fluxExtension = { + configurations: [ + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' + } + namespace: 'flux-system' + scope: 'cluster' + } + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/Azure/gitops-flux2-kustomize-helm-mt' + } + kustomizations: { + apps: { + dependsOn: [ + 'infra' + ] + path: './apps/staging' + prune: true + retryIntervalInSeconds: 120 + syncIntervalInSeconds: 600 + timeoutInSeconds: 600 + } + infra: { + dependsOn: [] + path: './infrastructure' + prune: true + syncIntervalInSeconds: 600 + timeoutInSeconds: 600 + validation: 'none' + } + } + namespace: 'flux-system-helm' + scope: 'cluster' + } + ] + configurationSettings: { + 'helm-controller.enabled': 'true' + 'image-automation-controller.enabled': 'false' + 'image-reflector-controller.enabled': 'false' + 'kustomize-controller.enabled': 'true' + 'notification-controller.enabled': 'true' + 'source-controller.enabled': 'true' + } +} +param identityProfile = { + kubeletidentity: { + resourceId: '' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param monitoringWorkspaceId = '' +param networkDataplane = 'azure' +param networkPlugin = 'azure' +param networkPluginMode = 'overlay' +param omsAgentEnabled = true +param openServiceMeshEnabled = true +param roleAssignments = [ + { + name: 'ac915208-669e-4665-9792-7e2dc861f569' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -690,7 +950,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -727,6 +987,33 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmin001' +param primaryAgentPoolProfile = [ + { + count: 3 + mode: 'System' + name: 'systempool' + vmSize: 'Standard_DS2_v2' + } +] +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
    +

    + ### Example 4: _Using Kubenet Network Plugin._ This instance deploys the module with Kubenet network plugin . @@ -860,7 +1147,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1003,6 +1290,129 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmkube001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 1 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param networkPlugin = 'kubenet' +param roleAssignments = [ + { + name: '6acf186b-abbd-491b-8bd7-39fa199da81e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 5: _Using Private Cluster._ This instance deploys the module with a private cluster instance. @@ -1105,7 +1515,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1221,6 +1631,98 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'csmpriv001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 1 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } + { + availabilityZones: [ + '3' + ] + count: 2 + enableAutoScaling: true + maxCount: 3 + maxPods: 30 + minCount: 1 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 128 + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +param dnsServiceIP = '10.10.200.10' +param enablePrivateCluster = true +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param networkPlugin = 'azure' +param privateDNSZone = '' +param serviceCidr = '10.10.200.0/24' +param skuTier = 'Standard' +``` + +
    +

    + ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -1364,7 +1866,7 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1537,6 +2039,139 @@ module managedCluster 'br/public:avm/res/container-service/managed-cluster:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/container-service/managed-cluster:' + +// Required parameters +param name = 'cswaf001' +param primaryAgentPoolProfile = [ + { + availabilityZones: [ + '3' + ] + count: 3 + enableAutoScaling: true + maxCount: 3 + maxPods: 50 + minCount: 3 + mode: 'System' + name: 'systempool' + nodeTaints: [ + 'CriticalAddonsOnly=true:NoSchedule' + ] + osDiskSizeGB: 0 + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } +] +// Non-required parameters +param agentPools = [ + { + availabilityZones: [ + '3' + ] + count: 3 + enableAutoScaling: true + maxCount: 3 + maxPods: 50 + minCount: 3 + minPods: 2 + mode: 'User' + name: 'userpool1' + nodeLabels: {} + osDiskSizeGB: 60 + osDiskType: 'Ephemeral' + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + vnetSubnetID: '' + } + { + availabilityZones: [ + '3' + ] + count: 3 + enableAutoScaling: true + maxCount: 3 + maxPods: 50 + minCount: 3 + minPods: 2 + mode: 'User' + name: 'userpool2' + nodeLabels: {} + osDiskSizeGB: 60 + osDiskType: 'Ephemeral' + osType: 'Linux' + scaleSetEvictionPolicy: 'Delete' + scaleSetPriority: 'Regular' + type: 'VirtualMachineScaleSets' + vmSize: 'Standard_DS2_v2' + } +] +param autoUpgradeProfileUpgradeChannel = 'stable' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'kube-apiserver' + } + { + category: 'kube-controller-manager' + } + { + category: 'kube-scheduler' + } + { + category: 'cluster-autoscaler' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAccounts = true +param dnsServiceIP = '10.10.200.10' +param enableAzureDefender = true +param enablePrivateCluster = true +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param monitoringWorkspaceId = '' +param networkPlugin = 'azure' +param networkPolicy = 'azure' +param omsAgentEnabled = true +param privateDNSZone = '' +param serviceCidr = '10.10.200.0/24' +param skuTier = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -3194,6 +3829,26 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Kubernetes Fleet Manager Contributor Role'` + - `'Azure Kubernetes Fleet Manager RBAC Admin'` + - `'Azure Kubernetes Fleet Manager RBAC Cluster Admin'` + - `'Azure Kubernetes Fleet Manager RBAC Reader'` + - `'Azure Kubernetes Fleet Manager RBAC Writer'` + - `'Azure Kubernetes Service Cluster Admin Role'` + - `'Azure Kubernetes Service Cluster Monitoring User'` + - `'Azure Kubernetes Service Cluster User Role'` + - `'Azure Kubernetes Service Contributor Role'` + - `'Azure Kubernetes Service RBAC Admin'` + - `'Azure Kubernetes Service RBAC Cluster Admin'` + - `'Azure Kubernetes Service RBAC Reader'` + - `'Azure Kubernetes Service RBAC Writer'` + - `'Contributor'` + - `'Kubernetes Agentless Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md index d4ee7144b0..6ac0a9c7ce 100644 --- a/avm/res/data-factory/factory/README.md +++ b/avm/res/data-factory/factory/README.md @@ -65,7 +65,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,22 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-factory/factory:' + +// Required parameters +param name = 'dffmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -165,7 +181,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = { } type: 'AzureBlobFS' typeProperties: { - url: '@{concat(\'https://\', linkedService().storageAccountName, \'.dfs.core.windows.net\')}' + url: '' } } ] @@ -250,7 +266,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -335,7 +351,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = { }, "type": "AzureBlobFS", "typeProperties": { - "url": "@{concat(\"https://\", linkedService().storageAccountName, \".dfs.core.windows.net\")}" + "url": "" } } ] @@ -435,6 +451,159 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-factory/factory:' + +// Required parameters +param name = 'dffmax001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gitConfigureLater = true +param globalParameters = { + testParameter1: { + type: 'String' + value: 'testValue1' + } +} +param integrationRuntimes = [ + { + name: 'TestRuntime' + type: 'SelfHosted' + } + { + managedVirtualNetworkName: 'default' + name: 'IRvnetManaged' + type: 'Managed' + typeProperties: { + computeProperties: { + location: 'AutoResolve' + } + } + } +] +param linkedServices = [ + { + name: 'SQLdbLinkedservice' + type: 'AzureSQLDatabase' + typeProperties: { + connectionString: '' + } + } + { + description: 'This is a description for the linked service using the IRvnetManaged integration runtime.' + integrationRuntimeName: 'IRvnetManaged' + name: 'LakeStoreLinkedservice' + parameters: { + storageAccountName: { + defaultValue: 'madeupstorageaccname' + type: 'String' + } + } + type: 'AzureBlobFS' + typeProperties: { + url: '' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param managedPrivateEndpoints = [ + { + fqdns: [ + '' + ] + groupId: 'blob' + name: '' + privateLinkResourceId: '' + } +] +param managedVirtualNetworkName = 'default' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + application: 'AVM' + 'hidden-title': 'This is visible in the resource name' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '12093237-f40a-4f36-868f-accbeebf540c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -481,7 +650,7 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -531,6 +700,42 @@ module factory 'br/public:avm/res/data-factory/factory:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-factory/factory:' + +// Required parameters +param name = 'dffwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gitConfigureLater = true +param integrationRuntimes = [ + { + name: 'TestRuntime' + type: 'SelfHosted' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -884,6 +1089,63 @@ An array of objects for the configuration of an Integration Runtime. - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-integrationruntimesname) | string | Specify the name of integration runtime. | +| [`type`](#parameter-integrationruntimestype) | string | Specify the type of the integration runtime. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`integrationRuntimeCustomDescription`](#parameter-integrationruntimesintegrationruntimecustomdescription) | string | Specify custom description for the integration runtime. | +| [`managedVirtualNetworkName`](#parameter-integrationruntimesmanagedvirtualnetworkname) | string | Specify managed vritual network name for the integration runtime to link to. | +| [`typeProperties`](#parameter-integrationruntimestypeproperties) | object | Integration Runtime type properties. Required if type is "Managed". | + +### Parameter: `integrationRuntimes.name` + +Specify the name of integration runtime. + +- Required: Yes +- Type: string + +### Parameter: `integrationRuntimes.type` + +Specify the type of the integration runtime. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Managed' + 'SelfHosted' + ] + ``` + +### Parameter: `integrationRuntimes.integrationRuntimeCustomDescription` + +Specify custom description for the integration runtime. + +- Required: No +- Type: string + +### Parameter: `integrationRuntimes.managedVirtualNetworkName` + +Specify managed vritual network name for the integration runtime to link to. + +- Required: No +- Type: string + +### Parameter: `integrationRuntimes.typeProperties` + +Integration Runtime type properties. Required if type is "Managed". + +- Required: No +- Type: object + ### Parameter: `linkedServices` An array of objects for the configuration of Linked Services. @@ -892,6 +1154,64 @@ An array of objects for the configuration of Linked Services. - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-linkedservicesname) | string | The name of the Linked Service. | +| [`type`](#parameter-linkedservicestype) | string | The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-linkedservicesdescription) | string | The description of the Integration Runtime. | +| [`integrationRuntimeName`](#parameter-linkedservicesintegrationruntimename) | string | The name of the Integration Runtime to use. | +| [`parameters`](#parameter-linkedservicesparameters) | object | Use this to add parameters for a linked service connection string. | +| [`typeProperties`](#parameter-linkedservicestypeproperties) | object | Used to add connection properties for your linked services. | + +### Parameter: `linkedServices.name` + +The name of the Linked Service. + +- Required: Yes +- Type: string + +### Parameter: `linkedServices.type` + +The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information. + +- Required: Yes +- Type: string + +### Parameter: `linkedServices.description` + +The description of the Integration Runtime. + +- Required: No +- Type: string + +### Parameter: `linkedServices.integrationRuntimeName` + +The name of the Integration Runtime to use. + +- Required: No +- Type: string + +### Parameter: `linkedServices.parameters` + +Use this to add parameters for a linked service connection string. + +- Required: No +- Type: object + +### Parameter: `linkedServices.typeProperties` + +Used to add connection properties for your linked services. + +- Required: No +- Type: object + ### Parameter: `location` Location for all Resources. @@ -972,6 +1292,48 @@ An array of managed private endpoints objects created in the Data Factory manage - Type: array - Default: `[]` +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-managedprivateendpointsgroupid) | string | Specify the sub-resource of the managed private endpoint. | +| [`name`](#parameter-managedprivateendpointsname) | string | Specify the name of managed private endpoint. | +| [`privateLinkResourceId`](#parameter-managedprivateendpointsprivatelinkresourceid) | string | Specify the resource ID to create the managed private endpoint for. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdns`](#parameter-managedprivateendpointsfqdns) | array | Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required. | + +### Parameter: `managedPrivateEndpoints.groupId` + +Specify the sub-resource of the managed private endpoint. + +- Required: Yes +- Type: string + +### Parameter: `managedPrivateEndpoints.name` + +Specify the name of managed private endpoint. + +- Required: Yes +- Type: string + +### Parameter: `managedPrivateEndpoints.privateLinkResourceId` + +Specify the resource ID to create the managed private endpoint for. + +- Required: Yes +- Type: string + +### Parameter: `managedPrivateEndpoints.fqdns` + +Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required. + +- Required: No +- Type: array + ### Parameter: `managedVirtualNetworkName` The name of the Managed Virtual Network. @@ -1270,6 +1632,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1397,6 +1770,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Data Factory Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/data-factory/factory/integration-runtime/main.json b/avm/res/data-factory/factory/integration-runtime/main.json index 991ffcaaa3..2db2b0af74 100644 --- a/avm/res/data-factory/factory/integration-runtime/main.json +++ b/avm/res/data-factory/factory/integration-runtime/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7050455062079134223" + "version": "0.30.23.60470", + "templateHash": "17201448291064419524" }, "name": "Data Factory Integration RunTimes", "description": "This module deploys a Data Factory Managed or Self-Hosted Integration Runtime.", diff --git a/avm/res/data-factory/factory/linked-service/main.bicep b/avm/res/data-factory/factory/linked-service/main.bicep index af51a01544..5748e4582f 100644 --- a/avm/res/data-factory/factory/linked-service/main.bicep +++ b/avm/res/data-factory/factory/linked-service/main.bicep @@ -41,6 +41,7 @@ resource linkedService 'Microsoft.DataFactory/factories/linkedservices@2018-06-0 referenceName: integrationRuntimeName type: 'IntegrationRuntimeReference' } + #disable-next-line BCP225 // false-positive as 'type' is interpreted as a syntax value type: type typeProperties: typeProperties parameters: parameters diff --git a/avm/res/data-factory/factory/linked-service/main.json b/avm/res/data-factory/factory/linked-service/main.json index c44e38f1ed..12ca641d7d 100644 --- a/avm/res/data-factory/factory/linked-service/main.json +++ b/avm/res/data-factory/factory/linked-service/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2964661488202892260" + "version": "0.30.23.60470", + "templateHash": "5456106394920661740" }, "name": "Data Factory Linked Service", "description": "This module deploys a Data Factory Linked Service.", diff --git a/avm/res/data-factory/factory/main.bicep b/avm/res/data-factory/factory/main.bicep index 7b24ccaf43..5bb934d5a0 100644 --- a/avm/res/data-factory/factory/main.bicep +++ b/avm/res/data-factory/factory/main.bicep @@ -9,13 +9,13 @@ param name string param managedVirtualNetworkName string = '' @description('Optional. An array of managed private endpoints objects created in the Data Factory managed virtual network.') -param managedPrivateEndpoints array = [] +param managedPrivateEndpoints managedPrivateEndpointType[] = [] @description('Optional. An array of objects for the configuration of an Integration Runtime.') -param integrationRuntimes array = [] +param integrationRuntimes integrationRuntimesType = [] @description('Optional. An array of objects for the configuration of Linked Services.') -param linkedServices array = [] +param linkedServices linkedServicesType = [] @description('Optional. Location for all Resources.') param location string = resourceGroup().location @@ -235,11 +235,9 @@ module dataFactory_integrationRuntimes 'integration-runtime/main.bicep' = [ dataFactoryName: dataFactory.name name: integrationRuntime.name type: integrationRuntime.type - integrationRuntimeCustomDescription: integrationRuntime.?integrationRuntimeCustomDescription ?? 'Managed Integration Runtime created by avm-res-datafactory-factories' - managedVirtualNetworkName: contains(integrationRuntime, 'managedVirtualNetworkName') - ? integrationRuntime.managedVirtualNetworkName - : '' - typeProperties: contains(integrationRuntime, 'typeProperties') ? integrationRuntime.typeProperties : {} + integrationRuntimeCustomDescription: integrationRuntime.?integrationRuntimeCustomDescription + managedVirtualNetworkName: integrationRuntime.?managedVirtualNetworkName + typeProperties: integrationRuntime.?typeProperties } dependsOn: [ dataFactory_managedVirtualNetwork @@ -259,6 +257,9 @@ module dataFactory_linkedServices 'linked-service/main.bicep' = [ parameters: linkedService.?parameters description: linkedService.?description } + dependsOn: [ + dataFactory_integrationRuntimes + ] } ] @@ -586,3 +587,54 @@ type customerManagedKeyType = { @description('Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use.') userAssignedIdentityResourceId: string? }? + +type managedPrivateEndpointType = { + @description('Required. Specify the name of managed private endpoint.') + name: string + + @description('Required. Specify the sub-resource of the managed private endpoint.') + groupId: string + + @description('Required. Specify the resource ID to create the managed private endpoint for.') + privateLinkResourceId: string + + @description('Optional. Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required.') + fqdns: string[]? +} + +type integrationRuntimesType = { + @description('Required. Specify the name of integration runtime.') + name: string + + @description('Required. Specify the type of the integration runtime.') + type: ('Managed' | 'SelfHosted') + + @description('Optional. Specify custom description for the integration runtime.') + integrationRuntimeCustomDescription: string? + + @description('Optional. Specify managed vritual network name for the integration runtime to link to.') + managedVirtualNetworkName: string? + + @description('Optional. Integration Runtime type properties. Required if type is "Managed".') + typeProperties: object? +}[] + +type linkedServicesType = { + @description('Required. The name of the Linked Service.') + name: string + + @description('Required. The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information.') + type: string + + @description('Optional. Used to add connection properties for your linked services.') + typeProperties: object? + + @description('Optional. The name of the Integration Runtime to use.') + integrationRuntimeName: string? + + @description('Optional. Use this to add parameters for a linked service connection string.') + parameters: object? + + @description('Optional. The description of the Integration Runtime.') + description: string? +}[] diff --git a/avm/res/data-factory/factory/main.json b/avm/res/data-factory/factory/main.json index 310b27936e..5e8ffea4e0 100644 --- a/avm/res/data-factory/factory/main.json +++ b/avm/res/data-factory/factory/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18076044993800210191" + "version": "0.30.23.60470", + "templateHash": "15687596888855868361" }, "name": "Data Factories", "description": "This module deploys a Data Factory.", @@ -505,6 +505,132 @@ } }, "nullable": true + }, + "managedPrivateEndpointType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specify the name of managed private endpoint." + } + }, + "groupId": { + "type": "string", + "metadata": { + "description": "Required. Specify the sub-resource of the managed private endpoint." + } + }, + "privateLinkResourceId": { + "type": "string", + "metadata": { + "description": "Required. Specify the resource ID to create the managed private endpoint for." + } + }, + "fqdns": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specify the FQDNS of the linked resources to create private endpoints for, depending on the type of linked resource this is required." + } + } + } + }, + "integrationRuntimesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specify the name of integration runtime." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Managed", + "SelfHosted" + ], + "metadata": { + "description": "Required. Specify the type of the integration runtime." + } + }, + "integrationRuntimeCustomDescription": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify custom description for the integration runtime." + } + }, + "managedVirtualNetworkName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify managed vritual network name for the integration runtime to link to." + } + }, + "typeProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Integration Runtime type properties. Required if type is \"Managed\"." + } + } + } + } + }, + "linkedServicesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Linked Service." + } + }, + "type": { + "type": "string", + "metadata": { + "description": "Required. The type of Linked Service. See https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories/linkedservices?pivots=deployment-language-bicep#linkedservice-objects for more information." + } + }, + "typeProperties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Used to add connection properties for your linked services." + } + }, + "integrationRuntimeName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Integration Runtime to use." + } + }, + "parameters": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Use this to add parameters for a linked service connection string." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the Integration Runtime." + } + } + } + } } }, "parameters": { @@ -523,20 +649,23 @@ }, "managedPrivateEndpoints": { "type": "array", + "items": { + "$ref": "#/definitions/managedPrivateEndpointType" + }, "defaultValue": [], "metadata": { "description": "Optional. An array of managed private endpoints objects created in the Data Factory managed virtual network." } }, "integrationRuntimes": { - "type": "array", + "$ref": "#/definitions/integrationRuntimesType", "defaultValue": [], "metadata": { "description": "Optional. An array of objects for the configuration of an Integration Runtime." } }, "linkedServices": { - "type": "array", + "$ref": "#/definitions/linkedServicesType", "defaultValue": [], "metadata": { "description": "Optional. An array of objects for the configuration of Linked Services." @@ -888,8 +1017,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17839923462414788715" + "version": "0.30.23.60470", + "templateHash": "1782105630855230474" }, "name": "Data Factory Managed Virtual Networks", "description": "This module deploys a Data Factory Managed Virtual Network.", @@ -962,8 +1091,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3694105160445163406" + "version": "0.30.23.60470", + "templateHash": "6720514642858120112" }, "name": "Data Factory Managed Virtual Network Managed PrivateEndpoints", "description": "This module deploys a Data Factory Managed Virtual Network Managed Private Endpoint.", @@ -1099,10 +1228,14 @@ "value": "[parameters('integrationRuntimes')[copyIndex()].type]" }, "integrationRuntimeCustomDescription": { - "value": "[coalesce(tryGet(parameters('integrationRuntimes')[copyIndex()], 'integrationRuntimeCustomDescription'), 'Managed Integration Runtime created by avm-res-datafactory-factories')]" + "value": "[tryGet(parameters('integrationRuntimes')[copyIndex()], 'integrationRuntimeCustomDescription')]" }, - "managedVirtualNetworkName": "[if(contains(parameters('integrationRuntimes')[copyIndex()], 'managedVirtualNetworkName'), createObject('value', parameters('integrationRuntimes')[copyIndex()].managedVirtualNetworkName), createObject('value', ''))]", - "typeProperties": "[if(contains(parameters('integrationRuntimes')[copyIndex()], 'typeProperties'), createObject('value', parameters('integrationRuntimes')[copyIndex()].typeProperties), createObject('value', createObject()))]" + "managedVirtualNetworkName": { + "value": "[tryGet(parameters('integrationRuntimes')[copyIndex()], 'managedVirtualNetworkName')]" + }, + "typeProperties": { + "value": "[tryGet(parameters('integrationRuntimes')[copyIndex()], 'typeProperties')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1110,8 +1243,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7050455062079134223" + "version": "0.30.23.60470", + "templateHash": "17201448291064419524" }, "name": "Data Factory Integration RunTimes", "description": "This module deploys a Data Factory Managed or Self-Hosted Integration Runtime.", @@ -1248,8 +1381,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2964661488202892260" + "version": "0.30.23.60470", + "templateHash": "5456106394920661740" }, "name": "Data Factory Linked Service", "description": "This module deploys a Data Factory Linked Service.", @@ -1344,7 +1477,8 @@ } }, "dependsOn": [ - "dataFactory" + "dataFactory", + "dataFactory_integrationRuntimes" ] }, "dataFactory_privateEndpoints": { diff --git a/avm/res/data-factory/factory/managed-virtual-network/main.json b/avm/res/data-factory/factory/managed-virtual-network/main.json index f84cc1629b..22a3f54962 100644 --- a/avm/res/data-factory/factory/managed-virtual-network/main.json +++ b/avm/res/data-factory/factory/managed-virtual-network/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17839923462414788715" + "version": "0.30.23.60470", + "templateHash": "1782105630855230474" }, "name": "Data Factory Managed Virtual Networks", "description": "This module deploys a Data Factory Managed Virtual Network.", @@ -78,8 +78,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3694105160445163406" + "version": "0.30.23.60470", + "templateHash": "6720514642858120112" }, "name": "Data Factory Managed Virtual Network Managed PrivateEndpoints", "description": "This module deploys a Data Factory Managed Virtual Network Managed Private Endpoint.", diff --git a/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json b/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json index 28c3cf639b..c9c9e60513 100644 --- a/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json +++ b/avm/res/data-factory/factory/managed-virtual-network/managed-private-endpoint/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3694105160445163406" + "version": "0.30.23.60470", + "templateHash": "6720514642858120112" }, "name": "Data Factory Managed Virtual Network Managed PrivateEndpoints", "description": "This module deploys a Data Factory Managed Virtual Network Managed Private Endpoint.", diff --git a/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep b/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep index 03a1f38a74..a134efefe6 100644 --- a/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep +++ b/avm/res/data-factory/factory/tests/e2e/max/main.test.bicep @@ -136,7 +136,7 @@ module testDeployment '../../../main.bicep' = [ } type: 'AzureBlobFS' typeProperties: { - url: '@{concat(\'https://\', linkedService().storageAccountName, \'.dfs.core.windows.net\')}' + url: '@{concat(\'https://\', linkedService().storageAccountName, \'.dfs.${environment().suffixes.storage}\')}' } } ] diff --git a/avm/res/data-protection/backup-vault/README.md b/avm/res/data-protection/backup-vault/README.md index 5ef4757a5b..b0ce4fac62 100644 --- a/avm/res/data-protection/backup-vault/README.md +++ b/avm/res/data-protection/backup-vault/README.md @@ -58,7 +58,7 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-protection/backup-vault:' + +// Required parameters +param name = 'dpbvmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -200,7 +216,7 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +344,116 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-protection/backup-vault:' + +// Required parameters +param name = 'dpbvmax001' +// Non-required parameters +param azureMonitorAlertSettingsAlertsForAllJobFailures = 'Disabled' +param backupPolicies = [ + { + name: 'DefaultPolicy' + properties: { + datasourceTypes: [ + 'Microsoft.Compute/disks' + ] + objectType: 'BackupPolicy' + policyRules: [ + { + backupParameters: { + backupType: 'Incremental' + objectType: 'AzureBackupParams' + } + dataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + name: 'BackupDaily' + objectType: 'AzureBackupRule' + trigger: { + objectType: 'ScheduleBasedTriggerContext' + schedule: { + repeatingTimeIntervals: [ + 'R/2022-05-31T23:30:00+01:00/P1D' + ] + timeZone: 'W. Europe Standard Time' + } + taggingCriteria: [ + { + isDefault: true + taggingPriority: 99 + tagInfo: { + id: 'Default_' + tagName: 'Default' + } + } + ] + } + } + { + isDefault: true + lifecycles: [ + { + deleteAfter: { + duration: 'P7D' + objectType: 'AbsoluteDeleteOption' + } + sourceDataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + targetDataStoreCopySettings: [] + } + ] + name: 'Default' + objectType: 'AzureRetentionRule' + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + name: 'cbc3932a-1bee-4318-ae76-d70e1ba399c8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -429,7 +555,7 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -536,6 +662,97 @@ module backupVault 'br/public:avm/res/data-protection/backup-vault:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/data-protection/backup-vault:' + +// Required parameters +param name = 'dpbvwaf001' +// Non-required parameters +param azureMonitorAlertSettingsAlertsForAllJobFailures = 'Disabled' +param backupPolicies = [ + { + name: 'DefaultPolicy' + properties: { + datasourceTypes: [ + 'Microsoft.Compute/disks' + ] + objectType: 'BackupPolicy' + policyRules: [ + { + backupParameters: { + backupType: 'Incremental' + objectType: 'AzureBackupParams' + } + dataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + name: 'BackupDaily' + objectType: 'AzureBackupRule' + trigger: { + objectType: 'ScheduleBasedTriggerContext' + schedule: { + repeatingTimeIntervals: [ + 'R/2022-05-31T23:30:00+01:00/P1D' + ] + timeZone: 'W. Europe Standard Time' + } + taggingCriteria: [ + { + isDefault: true + taggingPriority: 99 + tagInfo: { + id: 'Default_' + tagName: 'Default' + } + } + ] + } + } + { + isDefault: true + lifecycles: [ + { + deleteAfter: { + duration: 'P7D' + objectType: 'AbsoluteDeleteOption' + } + sourceDataStore: { + dataStoreType: 'OperationalStore' + objectType: 'DataStoreInfoBase' + } + targetDataStoreCopySettings: [] + } + ] + name: 'Default' + objectType: 'AzureRetentionRule' + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -693,6 +910,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Backup Contributor'` + - `'Backup Operator'` + - `'Backup Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/databricks/access-connector/README.md b/avm/res/databricks/access-connector/README.md index 5086b63cd6..cc2a54e83b 100644 --- a/avm/res/databricks/access-connector/README.md +++ b/avm/res/databricks/access-connector/README.md @@ -56,7 +56,7 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/access-connector:' + +// Required parameters +param name = 'dacmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -138,7 +154,7 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -202,6 +218,56 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/access-connector:' + +// Required parameters +param name = 'dacmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: 'e9143a6b-a031-419c-a597-cc4ac9bd39ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -240,7 +306,7 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -280,6 +346,34 @@ module accessConnector 'br/public:avm/res/databricks/access-connector:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/access-connector:' + +// Required parameters +param name = 'dacwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -392,6 +486,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index b3084f34a5..927dca6a7e 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -61,7 +61,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,22 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/workspace:' + +// Required parameters +param name = 'dwmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -212,7 +228,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -389,6 +405,125 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/workspace:' + +// Required parameters +param name = 'dwmax002' +// Non-required parameters +param amlWorkspaceResourceId = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param customerManagedKeyManagedDisk = { + keyName: '' + keyVaultResourceId: '' + rotationToLatestKeyVersionEnabled: true +} +param customPrivateSubnetName = '' +param customPublicSubnetName = '' +param customVirtualNetworkResourceId = '' +param defaultCatalog = { + initialType: 'UnityCatalog' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disablePublicIp = true +param loadBalancerBackendPoolName = '' +param loadBalancerResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedResourceGroupResourceId = '' +param natGatewayName = 'nat-gateway' +param prepareEncryption = true +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'databricks_ui_api' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'browser_authentication' + subnetResourceId: '' + } +] +param publicIpName = 'nat-gw-public-ip' +param publicNetworkAccess = 'Disabled' +param requiredNsgRules = 'NoAzureDatabricksRules' +param requireInfrastructureEncryption = true +param roleAssignments = [ + { + name: '2754e64b-b96e-44bc-9cb2-6e39b057f515' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'premium' +param storageAccountName = 'sadwmax001' +param storageAccountSkuName = 'Standard_ZRS' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vnetAddressPrefix = '10.100' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -500,7 +635,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -661,6 +796,107 @@ module workspace 'br/public:avm/res/databricks/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/databricks/workspace:' + +// Required parameters +param name = 'dwwaf001' +// Non-required parameters +param accessConnectorResourceId = '' +param amlWorkspaceResourceId = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param customerManagedKeyManagedDisk = { + keyName: '' + keyVaultResourceId: '' + rotationToLatestKeyVersionEnabled: true +} +param customPrivateSubnetName = '' +param customPublicSubnetName = '' +param customVirtualNetworkResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disablePublicIp = true +param loadBalancerBackendPoolName = '' +param loadBalancerResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedResourceGroupResourceId = '' +param natGatewayName = 'nat-gateway' +param prepareEncryption = true +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'databricks_ui_api' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param privateStorageAccount = 'Enabled' +param publicIpName = 'nat-gw-public-ip' +param publicNetworkAccess = 'Disabled' +param requiredNsgRules = 'NoAzureDatabricksRules' +param requireInfrastructureEncryption = true +param skuName = 'premium' +param storageAccountName = 'sadwwaf001' +param storageAccountPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param storageAccountSkuName = 'Standard_ZRS' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vnetAddressPrefix = '10.100' +``` + +
    +

    + ## Parameters **Required parameters** @@ -1565,6 +1801,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1977,6 +2219,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/db-for-my-sql/flexible-server/README.md b/avm/res/db-for-my-sql/flexible-server/README.md index f915bedd9d..bda2a9c1e3 100644 --- a/avm/res/db-for-my-sql/flexible-server/README.md +++ b/avm/res/db-for-my-sql/flexible-server/README.md @@ -16,7 +16,7 @@ This module deploys a DBforMySQL Flexible Server. | :-- | :-- | | `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.DBforMySQL/flexibleServers` | [2023-12-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/flexibleServers) | +| `Microsoft.DBforMySQL/flexibleServers` | [2023-12-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-12-30/flexibleServers) | | `Microsoft.DBforMySQL/flexibleServers/administrators` | [2023-06-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-06-30/flexibleServers/administrators) | | `Microsoft.DBforMySQL/flexibleServers/databases` | [2023-06-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-06-30/flexibleServers/databases) | | `Microsoft.DBforMySQL/flexibleServers/firewallRules` | [2023-06-30](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DBforMySQL/2023-06-30/flexibleServers/firewallRules) | @@ -66,7 +66,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -103,6 +103,27 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmsfsmin001' +param skuName = 'Standard_D2ds_v4' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param location = '' +param storageAutoGrow = 'Enabled' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -227,7 +248,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -391,6 +412,120 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmsmax001' +param skuName = 'Standard_D2ads_v5' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param availabilityZone = '1' +param backupRetentionDays = 20 +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param customerManagedKeyGeo = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param databases = [ + { + name: 'testdb1' + } + { + charset: 'ascii' + collation: 'ascii_general_ci' + name: 'testdb2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallRules = [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } + { + endIpAddress: '10.10.10.10' + name: 'test-rule1' + startIpAddress: '10.10.10.1' + } + { + endIpAddress: '100.100.100.10' + name: 'test-rule2' + startIpAddress: '100.100.100.1' + } +] +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + '' + ] +} +param roleAssignments = [ + { + name: '2478b63b-0cae-457f-9bd3-9feb00e1925b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageAutoGrow = 'Enabled' +param storageAutoIoScaling = 'Enabled' +param storageIOPS = 400 +param storageSizeGB = 64 +param tags = { + 'hidden-title': 'This is visible in the resource name' + resourceType: 'MySQL Flexible Server' + serverName: 'dfmsmax001' +} +param version = '8.0.21' +``` + +
    +

    + ### Example 3: _Deploys in connectivity mode "Private Access"_ This instance deploys the module with connectivity mode "Private Access". @@ -446,7 +581,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -527,6 +662,51 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmspvt001' +param skuName = 'Standard_D2ds_v4' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param administrators = [ + { + identityResourceId: '' + login: '' + sid: '' + } +] +param backupRetentionDays = 10 +param databases = [ + { + name: 'testdb1' + } +] +param delegatedSubnetResourceId = '' +param highAvailability = 'SameZone' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param privateDnsZoneResourceId = '' +param storageAutoGrow = 'Enabled' +param storageAutoIoScaling = 'Enabled' +param storageIOPS = 400 +param storageSizeGB = 64 +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -570,7 +750,7 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -629,6 +809,39 @@ module flexibleServer 'br/public:avm/res/db-for-my-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-my-sql/flexible-server:' + +// Required parameters +param name = 'dfmswaf001' +param skuName = 'Standard_D2ds_v4' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param availabilityZone = '1' +param highAvailability = 'ZoneRedundant' +param highAvailabilityZone = '2' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param storageAutoGrow = 'Enabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1223,6 +1436,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'MySQL Backup And Export Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/db-for-my-sql/flexible-server/administrator/main.json b/avm/res/db-for-my-sql/flexible-server/administrator/main.json index a08e31dfad..e01bbabdc8 100644 --- a/avm/res/db-for-my-sql/flexible-server/administrator/main.json +++ b/avm/res/db-for-my-sql/flexible-server/administrator/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "166868353165081250" + "version": "0.30.3.12046", + "templateHash": "17380647846007156110" }, "name": "DBforMySQL Flexible Server Administrators", "description": "This module deploys a DBforMySQL Flexible Server Administrator.", diff --git a/avm/res/db-for-my-sql/flexible-server/database/main.json b/avm/res/db-for-my-sql/flexible-server/database/main.json index 3ecb2da053..de30c026df 100644 --- a/avm/res/db-for-my-sql/flexible-server/database/main.json +++ b/avm/res/db-for-my-sql/flexible-server/database/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11351866916144767840" + "version": "0.30.3.12046", + "templateHash": "15491679806037869848" }, "name": "DBforMySQL Flexible Server Databases", "description": "This module deploys a DBforMySQL Flexible Server Database.", diff --git a/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json b/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json index 06fc052a20..a79df47833 100644 --- a/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json +++ b/avm/res/db-for-my-sql/flexible-server/firewall-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17406464450077393680" + "version": "0.30.3.12046", + "templateHash": "10498063087675421166" }, "name": "DBforMySQL Flexible Server Firewall Rules", "description": "This module deploys a DBforMySQL Flexible Server Firewall Rule.", diff --git a/avm/res/db-for-my-sql/flexible-server/main.bicep b/avm/res/db-for-my-sql/flexible-server/main.bicep index 0cdfde042a..cea96cf71d 100644 --- a/avm/res/db-for-my-sql/flexible-server/main.bicep +++ b/avm/res/db-for-my-sql/flexible-server/main.bicep @@ -371,8 +371,8 @@ module flexibleServer_databases 'database/main.bicep' = [ params: { name: database.name flexibleServerName: flexibleServer.name - collation: contains(database, 'collation') ? database.collation : '' - charset: contains(database, 'charset') ? database.charset : '' + collation: database.?collation ?? '' + charset: database.?charset ?? '' } } ] @@ -397,7 +397,7 @@ module flexibleServer_administrators 'administrator/main.bicep' = [ login: administrator.login sid: administrator.sid identityResourceId: administrator.identityResourceId - tenantId: contains(administrator, 'tenantId') ? administrator.tenantId : tenant().tenantId + tenantId: administrator.?tenantId ?? tenant().tenantId } } ] diff --git a/avm/res/db-for-my-sql/flexible-server/main.json b/avm/res/db-for-my-sql/flexible-server/main.json index ba56f19217..4073cc3021 100644 --- a/avm/res/db-for-my-sql/flexible-server/main.json +++ b/avm/res/db-for-my-sql/flexible-server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4552759122514680729" + "version": "0.30.3.12046", + "templateHash": "17022862459992031093" }, "name": "DBforMySQL Flexible Servers", "description": "This module deploys a DBforMySQL Flexible Server.", @@ -817,8 +817,12 @@ "flexibleServerName": { "value": "[parameters('name')]" }, - "collation": "[if(contains(parameters('databases')[copyIndex()], 'collation'), createObject('value', parameters('databases')[copyIndex()].collation), createObject('value', ''))]", - "charset": "[if(contains(parameters('databases')[copyIndex()], 'charset'), createObject('value', parameters('databases')[copyIndex()].charset), createObject('value', ''))]" + "collation": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'collation'), '')]" + }, + "charset": { + "value": "[coalesce(tryGet(parameters('databases')[copyIndex()], 'charset'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -826,8 +830,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11351866916144767840" + "version": "0.30.3.12046", + "templateHash": "15491679806037869848" }, "name": "DBforMySQL Flexible Server Databases", "description": "This module deploys a DBforMySQL Flexible Server Database.", @@ -934,8 +938,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17406464450077393680" + "version": "0.30.3.12046", + "templateHash": "10498063087675421166" }, "name": "DBforMySQL Flexible Server Firewall Rules", "description": "This module deploys a DBforMySQL Flexible Server Firewall Rule.", @@ -1033,7 +1037,9 @@ "identityResourceId": { "value": "[parameters('administrators')[copyIndex()].identityResourceId]" }, - "tenantId": "[if(contains(parameters('administrators')[copyIndex()], 'tenantId'), createObject('value', parameters('administrators')[copyIndex()].tenantId), createObject('value', tenant().tenantId))]" + "tenantId": { + "value": "[coalesce(tryGet(parameters('administrators')[copyIndex()], 'tenantId'), tenant().tenantId)]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1041,8 +1047,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "166868353165081250" + "version": "0.30.3.12046", + "templateHash": "17380647846007156110" }, "name": "DBforMySQL Flexible Server Administrators", "description": "This module deploys a DBforMySQL Flexible Server Administrator.", diff --git a/avm/res/db-for-postgre-sql/flexible-server/README.md b/avm/res/db-for-postgre-sql/flexible-server/README.md index 8e84071338..ec83051aaa 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/README.md +++ b/avm/res/db-for-postgre-sql/flexible-server/README.md @@ -74,7 +74,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -117,6 +117,33 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfsmin001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administrators = [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } +] +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +``` + +
    +

    + ### Example 2: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -157,7 +184,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -205,6 +232,36 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfse001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +``` + +
    +

    + ### Example 3: _Private access_ This instance deploys the module with private access only. @@ -296,7 +353,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +464,87 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfspvt001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param configurations = [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } +] +param databases = [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } +] +param delegatedSubnetResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param geoRedundantBackup = 'Enabled' +param location = '' +param privateDnsZoneArmResourceId = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _Public access_ This instance deploys the module with public access. @@ -517,7 +655,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -651,6 +789,106 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfsp001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administrators = [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } +] +param backupRetentionDays = 20 +param configurations = [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } +] +param databases = [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param firewallRules = [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } + { + endIpAddress: '10.10.10.10' + name: 'test-rule1' + startIpAddress: '10.10.10.1' + } + { + endIpAddress: '100.100.100.10' + name: 'test-rule2' + startIpAddress: '100.100.100.1' + } +] +param geoRedundantBackup = 'Disabled' +param highAvailability = 'SameZone' +param location = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageSizeGB = 1024 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param version = '14' +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -731,7 +969,7 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -831,6 +1069,76 @@ module flexibleServer 'br/public:avm/res/db-for-postgre-sql/flexible-server:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/db-for-postgre-sql/flexible-server:' + +// Required parameters +param name = 'dfpsfswaf001' +param skuName = 'Standard_D2s_v3' +param tier = 'GeneralPurpose' +// Non-required parameters +param administrators = [ + { + objectId: '' + principalName: '' + principalType: 'ServicePrincipal' + } +] +param configurations = [ + { + name: 'log_min_messages' + source: 'user-override' + value: 'INFO' + } + { + name: 'autovacuum_naptime' + source: 'user-override' + value: '80' + } +] +param databases = [ + { + charset: 'UTF8' + collation: 'en_US.utf8' + name: 'testdb1' + } + { + name: 'testdb2' + } +] +param delegatedSubnetResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param geoRedundantBackup = 'Enabled' +param highAvailability = 'ZoneRedundant' +param location = '' +param maintenanceWindow = { + customWindow: 'Enabled' + dayOfWeek: 0 + startHour: 1 + startMinute: 0 +} +param privateDnsZoneArmResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1381,6 +1689,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.bicep b/avm/res/db-for-postgre-sql/flexible-server/main.bicep index 19c07e2e2f..7b24eb2bc7 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.bicep +++ b/avm/res/db-for-postgre-sql/flexible-server/main.bicep @@ -377,6 +377,9 @@ module flexibleServer_administrators 'administrator/main.bicep' = [ principalType: administrator.principalType tenantId: administrator.?tenantId ?? tenant().tenantId } + dependsOn: [ + flexibleServer_configurations + ] } ] diff --git a/avm/res/db-for-postgre-sql/flexible-server/main.json b/avm/res/db-for-postgre-sql/flexible-server/main.json index 9472f5d8f9..3e71af1f04 100644 --- a/avm/res/db-for-postgre-sql/flexible-server/main.json +++ b/avm/res/db-for-postgre-sql/flexible-server/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "745168326315156090" + "templateHash": "16193893481581771669" }, "name": "DBforPostgreSQL Flexible Servers", "description": "This module deploys a DBforPostgreSQL Flexible Server.", @@ -1193,7 +1193,8 @@ } }, "dependsOn": [ - "flexibleServer" + "flexibleServer", + "flexibleServer_configurations" ] } }, diff --git a/avm/res/desktop-virtualization/application-group/README.md b/avm/res/desktop-virtualization/application-group/README.md index 96040b8018..2ece1d6fa8 100644 --- a/avm/res/desktop-virtualization/application-group/README.md +++ b/avm/res/desktop-virtualization/application-group/README.md @@ -60,7 +60,7 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

    -via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,24 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/application-group:' + +// Required parameters +param applicationGroupType = 'Desktop' +param hostpoolName = '' +param name = 'dvagmin002' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -177,7 +195,7 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

    -via JSON Parameter file +via JSON parameters file ```json { @@ -278,6 +296,85 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/application-group:' + +// Required parameters +param applicationGroupType = 'RemoteApp' +param hostpoolName = '' +param name = 'dvagmax002' +// Non-required parameters +param applications = [ + { + commandLineArguments: '' + commandLineSetting: 'DoNotAllow' + description: 'Notepad by ARM template' + filePath: 'C:\\Windows\\System32\\notepad.exe' + friendlyName: 'Notepad' + iconIndex: 0 + iconPath: 'C:\\Windows\\System32\\notepad.exe' + name: 'notepad' + showInPortal: true + } + { + filePath: 'C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe' + friendlyName: 'Wordpad' + name: 'wordpad' + } +] +param description = 'myDescription' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '30eaf006-ee2d-4a95-921c-87dfdb4c2061' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 Well-Architected Framework. @@ -318,7 +415,7 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

    -via JSON Parameter file +via JSON parameters file ```json { @@ -362,6 +459,36 @@ module applicationGroup 'br/public:avm/res/desktop-virtualization/application-gr

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/application-group:' + +// Required parameters +param applicationGroupType = 'Desktop' +param hostpoolName = '' +param name = 'dvagwaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -608,6 +735,29 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + - `'Managed Application Contributor Role'` + - `'Managed Application Operator Role'` + - `'Managed Applications Reader'` **Required parameters** diff --git a/avm/res/desktop-virtualization/host-pool/README.md b/avm/res/desktop-virtualization/host-pool/README.md index 2d0ab9b957..094d7b8fad 100644 --- a/avm/res/desktop-virtualization/host-pool/README.md +++ b/avm/res/desktop-virtualization/host-pool/README.md @@ -60,7 +60,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/host-pool:' + +// Required parameters +param name = 'dvhpmin002' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -213,7 +229,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -372,6 +388,127 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/host-pool:' + +// Required parameters +param name = 'dvhpmax001' +// Non-required parameters +param agentUpdate = { + maintenanceWindows: [ + { + dayOfWeek: 'Friday' + hour: 7 + } + { + dayOfWeek: 'Saturday' + hour: 8 + } + ] + maintenanceWindowTimeZone: 'Alaskan Standard Time' + type: 'Scheduled' + useSessionHostLocalTime: false +} +param customRdpProperty = 'audiocapturemode:i:1;audiomode:i:0;drivestoredirect:s:;redirectclipboard:i:1;redirectcomports:i:1;redirectprinters:i:1;redirectsmartcards:i:1;screen mode id:i:2;' +param description = 'My first AVD Host Pool' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableTelemetry = true +param friendlyName = 'AVDv2' +param hostPoolType = 'Pooled' +param loadBalancerType = 'BreadthFirst' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maxSessionLimit = 99999 +param personalDesktopAssignmentType = 'Automatic' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '52c43567-917f-4c56-8c9b-6cadeef37b51' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vmTemplate = { + customImageId: '' + domain: 'domainname.onmicrosoft.com' + galleryImageOffer: 'office-365' + galleryImagePublisher: 'microsoftwindowsdesktop' + galleryImageSKU: '20h1-evd-o365pp' + imageType: 'Gallery' + imageUri: '' + namePrefix: 'avdv2' + osDiskType: 'StandardSSD_LRS' + useManagedDisks: true + vmSize: { + cores: 2 + id: 'Standard_D2s_v3' + ram: 8 + } +} +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -411,7 +548,7 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -450,6 +587,35 @@ module hostPool 'br/public:avm/res/desktop-virtualization/host-pool:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/host-pool:' + +// Required parameters +param name = 'dvhpwaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1071,6 +1237,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1207,6 +1384,29 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` + - `'Managed Application Contributor Role'` + - `'Managed Application Operator Role'` + - `'Managed Applications Reader'` **Required parameters** diff --git a/avm/res/desktop-virtualization/scaling-plan/README.md b/avm/res/desktop-virtualization/scaling-plan/README.md index a3860a3213..4482d692f6 100644 --- a/avm/res/desktop-virtualization/scaling-plan/README.md +++ b/avm/res/desktop-virtualization/scaling-plan/README.md @@ -57,7 +57,7 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/scaling-plan:' + +// Required parameters +param name = 'dvspmin002' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -263,7 +279,7 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -459,6 +475,180 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/scaling-plan:' + +// Required parameters +param name = 'dvspmax002' +// Non-required parameters +param description = 'myDescription' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param friendlyName = 'friendlyName' +param hostPoolReferences = [ + { + hostPoolArmPath: '' + scalingPlanEnabled: true + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'c2c1c560-2169-405a-a8dc-7427e403e5ac' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param schedules = [ + { + daysOfWeek: [ + 'Friday' + 'Monday' + 'Thursday' + 'Wednesday' + ] + name: 'WeekdaySchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 18 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Tuesday' + ] + name: 'weekdaysSchedule-agent-updates' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 20 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 9 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 19 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 80 + rampUpLoadBalancingAlgorithm: 'BreadthFirst' + rampUpMinimumHostsPct: 20 + rampUpStartTime: { + hour: 7 + minute: 0 + } + } + { + daysOfWeek: [ + 'Saturday' + 'Sunday' + ] + name: 'WeekendSchedule' + offPeakLoadBalancingAlgorithm: 'DepthFirst' + offPeakStartTime: { + hour: 18 + minute: 0 + } + peakLoadBalancingAlgorithm: 'DepthFirst' + peakStartTime: { + hour: 10 + minute: 0 + } + rampDownCapacityThresholdPct: 90 + rampDownForceLogoffUsers: true + rampDownLoadBalancingAlgorithm: 'DepthFirst' + rampDownMinimumHostsPct: 0 + rampDownNotificationMessage: 'You will be logged off in 30 min. Make sure to save your work.' + rampDownStartTime: { + hour: 16 + minute: 0 + } + rampDownStopHostsWhen: 'ZeroActiveSessions' + rampDownWaitTimeMinutes: 30 + rampUpCapacityThresholdPct: 90 + rampUpLoadBalancingAlgorithm: 'DepthFirst' + rampUpMinimumHostsPct: 0 + rampUpStartTime: { + hour: 9 + minute: 0 + } + } +] +param tags = { + 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. @@ -500,7 +690,7 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -545,6 +735,37 @@ module scalingPlan 'br/public:avm/res/desktop-virtualization/scaling-plan:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/scaling-plan:' + +// Required parameters +param name = 'dvspwaf002' +// Non-required parameters +param description = 'myDescription' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param friendlyName = 'myFriendlyName' +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -795,6 +1016,26 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` **Required parameters** diff --git a/avm/res/desktop-virtualization/workspace/README.md b/avm/res/desktop-virtualization/workspace/README.md index f37ac6ade8..bc71f372f4 100644 --- a/avm/res/desktop-virtualization/workspace/README.md +++ b/avm/res/desktop-virtualization/workspace/README.md @@ -60,7 +60,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/workspace:' + +// Required parameters +param name = 'dvwsmin002' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -231,7 +247,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -392,6 +408,145 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/workspace:' + +// Required parameters +param name = 'dvwsmax001' +// Non-required parameters +param applicationGroupReferences = [] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param friendlyName = 'AVD Workspace' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + customDnsConfigs: [] + ipConfigurations: [ + { + name: 'myIPconfig-feed1' + properties: { + groupId: 'feed' + memberName: 'web-r0' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-feed2' + properties: { + groupId: 'feed' + memberName: 'web-r1' + privateIPAddress: '10.0.0.13' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + service: 'feed' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + customDnsConfigs: [] + ipConfigurations: [ + { + name: 'myIPconfig-global' + properties: { + groupId: 'global' + memberName: 'web' + privateIPAddress: '10.0.0.11' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + service: 'global' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: 'e31e3fcd-816f-49b9-a741-feff792a56d7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 Well-Architected Framework. @@ -431,7 +586,7 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -470,6 +625,35 @@ module workspace 'br/public:avm/res/desktop-virtualization/workspace:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/desktop-virtualization/workspace:' + +// Required parameters +param name = 'dvwswaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -971,6 +1155,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1090,6 +1285,26 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Owner'` + - `'Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Application Group Contributor'` + - `'Desktop Virtualization Application Group Contributor'` + - `'Desktop Virtualization Application Group Reader'` + - `'Desktop Virtualization Contributor'` + - `'Desktop Virtualization Host Pool Contributor'` + - `'Desktop Virtualization Host Pool Reader'` + - `'Desktop Virtualization Power On Off Contributor'` + - `'Desktop Virtualization Reader'` + - `'Desktop Virtualization Session Host Operator'` + - `'Desktop Virtualization User'` + - `'Desktop Virtualization User Session Operator'` + - `'Desktop Virtualization Virtual Machine Contributor'` + - `'Desktop Virtualization Workspace Contributor'` + - `'Desktop Virtualization Workspace Reader'` **Required parameters** diff --git a/avm/res/dev-ops-infrastructure/pool/README.md b/avm/res/dev-ops-infrastructure/pool/README.md new file mode 100644 index 0000000000..dee3ec1d9f --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/README.md @@ -0,0 +1,1531 @@ +# Managed DevOps Pool `[Microsoft.DevOpsInfrastructure/pools]` + +This module deploys the Managed DevOps Pool resource. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Notes](#Notes) +- [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.DevOpsInfrastructure/pools` | [2024-04-04-preview](https://learn.microsoft.com/en-us/azure/templates) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | + +## 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/dev-ops-infrastructure/pool:`. + +- [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 pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = { + name: 'poolDeployment' + params: { + // Required parameters + agentProfile: { + kind: 'Stateless' + } + concurrency: 1 + devCenterProjectResourceId: '' + fabricProfileSkuName: 'Standard_DS2_v2' + images: [ + { + wellKnownImageName: 'windows-2022/latest' + } + ] + name: 'mdpmin001' + organizationProfile: { + kind: 'AzureDevOps' + organizations: [ + { + url: '' + } + ] + } + // Non-required parameters + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "agentProfile": { + "value": { + "kind": "Stateless" + } + }, + "concurrency": { + "value": 1 + }, + "devCenterProjectResourceId": { + "value": "" + }, + "fabricProfileSkuName": { + "value": "Standard_DS2_v2" + }, + "images": { + "value": [ + { + "wellKnownImageName": "windows-2022/latest" + } + ] + }, + "name": { + "value": "mdpmin001" + }, + "organizationProfile": { + "value": { + "kind": "AzureDevOps", + "organizations": [ + { + "url": "" + } + ] + } + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/dev-ops-infrastructure/pool:' + +// Required parameters +param agentProfile = { + kind: 'Stateless' +} +param concurrency = 1 +param devCenterProjectResourceId = '' +param fabricProfileSkuName = 'Standard_DS2_v2' +param images = [ + { + wellKnownImageName: 'windows-2022/latest' + } +] +param name = 'mdpmin001' +param organizationProfile = { + kind: 'AzureDevOps' + organizations: [ + { + url: '' + } + ] +} +// Non-required parameters +param location = '' +``` + +
    +

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

    + +via Bicep module + +```bicep +module pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = { + name: 'poolDeployment' + params: { + // Required parameters + agentProfile: { + kind: 'Stateless' + resourcePredictions: { + daysData: [ + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + {} + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + ] + timeZone: 'Central Europe Standard Time' + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } + } + concurrency: 1 + devCenterProjectResourceId: '' + fabricProfileSkuName: 'Standard_D2_v2' + images: [ + { + aliases: [ + 'windows-2022' + ] + buffer: '*' + wellKnownImageName: 'windows-2022/latest' + } + ] + name: 'mdpmax001' + organizationProfile: { + kind: 'AzureDevOps' + organizations: [ + { + parallelism: 1 + projects: [ + '' + ] + url: '' + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } + } + // Non-required parameters + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + ] + storageProfile: { + dataDisks: [ + { + caching: 'ReadWrite' + diskSizeGiB: 100 + driveLetter: 'B' + storageAccountType: 'Standard_LRS' + } + ] + osDiskStorageAccountType: 'Standard' + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "agentProfile": { + "value": { + "kind": "Stateless", + "resourcePredictions": { + "daysData": [ + { + "09:00:00": 1, + "17:00:00": 0 + }, + {}, + {}, + {}, + { + "09:00:00": 1, + "17:00:00": 0 + }, + {}, + {} + ], + "timeZone": "Central Europe Standard Time" + }, + "resourcePredictionsProfile": { + "kind": "Automatic", + "predictionPreference": "Balanced" + } + } + }, + "concurrency": { + "value": 1 + }, + "devCenterProjectResourceId": { + "value": "" + }, + "fabricProfileSkuName": { + "value": "Standard_D2_v2" + }, + "images": { + "value": [ + { + "aliases": [ + "windows-2022" + ], + "buffer": "*", + "wellKnownImageName": "windows-2022/latest" + } + ] + }, + "name": { + "value": "mdpmax001" + }, + "organizationProfile": { + "value": { + "kind": "AzureDevOps", + "organizations": [ + { + "parallelism": 1, + "projects": [ + "" + ], + "url": "" + } + ], + "permissionProfile": { + "kind": "CreatorOnly" + } + } + }, + // Non-required parameters + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + } + ] + }, + "storageProfile": { + "value": { + "dataDisks": [ + { + "caching": "ReadWrite", + "diskSizeGiB": 100, + "driveLetter": "B", + "storageAccountType": "Standard_LRS" + } + ], + "osDiskStorageAccountType": "Standard" + } + }, + "subnetResourceId": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/dev-ops-infrastructure/pool:' + +// Required parameters +param agentProfile = { + kind: 'Stateless' + resourcePredictions: { + daysData: [ + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + {} + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + ] + timeZone: 'Central Europe Standard Time' + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } +} +param concurrency = 1 +param devCenterProjectResourceId = '' +param fabricProfileSkuName = 'Standard_D2_v2' +param images = [ + { + aliases: [ + 'windows-2022' + ] + buffer: '*' + wellKnownImageName: 'windows-2022/latest' + } +] +param name = 'mdpmax001' +param organizationProfile = { + kind: 'AzureDevOps' + organizations: [ + { + parallelism: 1 + projects: [ + '' + ] + url: '' + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } +} +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } +] +param storageProfile = { + dataDisks: [ + { + caching: 'ReadWrite' + diskSizeGiB: 100 + driveLetter: 'B' + storageAccountType: 'Standard_LRS' + } + ] + osDiskStorageAccountType: 'Standard' +} +param subnetResourceId = '' +param tags = { + 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 pool 'br/public:avm/res/dev-ops-infrastructure/pool:' = { + name: 'poolDeployment' + params: { + // Required parameters + agentProfile: { + kind: 'Stateless' + resourcePredictions: { + daysData: [ + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + {} + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + ] + timeZone: 'Central Europe Standard Time' + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } + } + concurrency: 1 + devCenterProjectResourceId: '' + fabricProfileSkuName: 'Standard_D2_v2' + images: [ + { + wellKnownImageName: 'windows-2022/latest' + } + ] + name: 'mdpwaf001' + organizationProfile: { + kind: 'AzureDevOps' + organizations: [ + { + parallelism: 1 + projects: [ + '' + ] + url: '' + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } + } + // Non-required parameters + location: '' + subnetResourceId: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "agentProfile": { + "value": { + "kind": "Stateless", + "resourcePredictions": { + "daysData": [ + { + "09:00:00": 1, + "17:00:00": 0 + }, + {}, + {}, + {}, + { + "09:00:00": 1, + "17:00:00": 0 + }, + {}, + {} + ], + "timeZone": "Central Europe Standard Time" + }, + "resourcePredictionsProfile": { + "kind": "Automatic", + "predictionPreference": "Balanced" + } + } + }, + "concurrency": { + "value": 1 + }, + "devCenterProjectResourceId": { + "value": "" + }, + "fabricProfileSkuName": { + "value": "Standard_D2_v2" + }, + "images": { + "value": [ + { + "wellKnownImageName": "windows-2022/latest" + } + ] + }, + "name": { + "value": "mdpwaf001" + }, + "organizationProfile": { + "value": { + "kind": "AzureDevOps", + "organizations": [ + { + "parallelism": 1, + "projects": [ + "" + ], + "url": "" + } + ], + "permissionProfile": { + "kind": "CreatorOnly" + } + } + }, + // Non-required parameters + "location": { + "value": "" + }, + "subnetResourceId": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/dev-ops-infrastructure/pool:' + +// Required parameters +param agentProfile = { + kind: 'Stateless' + resourcePredictions: { + daysData: [ + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + {} + { + '09:00:00': 1 + '17:00:00': 0 + } + {} + {} + ] + timeZone: 'Central Europe Standard Time' + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } +} +param concurrency = 1 +param devCenterProjectResourceId = '' +param fabricProfileSkuName = 'Standard_D2_v2' +param images = [ + { + wellKnownImageName: 'windows-2022/latest' + } +] +param name = 'mdpwaf001' +param organizationProfile = { + kind: 'AzureDevOps' + organizations: [ + { + parallelism: 1 + projects: [ + '' + ] + url: '' + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } +} +// Non-required parameters +param location = '' +param subnetResourceId = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`agentProfile`](#parameter-agentprofile) | object | Defines how the machine will be handled once it executed a job. | +| [`concurrency`](#parameter-concurrency) | int | Defines how many resources can there be created at any given time. | +| [`devCenterProjectResourceId`](#parameter-devcenterprojectresourceid) | string | The resource id of the DevCenter Project the pool belongs to. | +| [`fabricProfileSkuName`](#parameter-fabricprofileskuname) | string | The Azure SKU name of the machines in the pool. | +| [`images`](#parameter-images) | array | The VM images of the machines in the pool. | +| [`name`](#parameter-name) | string | Name of the pool. It needs to be globally unique. | +| [`organizationProfile`](#parameter-organizationprofile) | object | Defines the organization in which the pool will be used. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | The geo-location where the resource lives. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed service identities assigned to this resource. | +| [`osProfile`](#parameter-osprofile) | object | The OS profile of the agents in the pool. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`storageProfile`](#parameter-storageprofile) | object | The storage profile of the machines in the pool. | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | The subnet id on which to put all machines created in the pool. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `agentProfile` + +Defines how the machine will be handled once it executed a job. + +- Required: Yes +- Type: object + +### Parameter: `concurrency` + +Defines how many resources can there be created at any given time. + +- Required: Yes +- Type: int + +### Parameter: `devCenterProjectResourceId` + +The resource id of the DevCenter Project the pool belongs to. + +- Required: Yes +- Type: string + +### Parameter: `fabricProfileSkuName` + +The Azure SKU name of the machines in the pool. + +- Required: Yes +- Type: string + +### Parameter: `images` + +The VM images of the machines in the pool. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`wellKnownImageName`](#parameter-imageswellknownimagename) | string | The image to use from a well-known set of images made available to customers. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aliases`](#parameter-imagesaliases) | array | List of aliases to reference the image by. | +| [`buffer`](#parameter-imagesbuffer) | string | The percentage of the buffer to be allocated to this image. | +| [`resourceId`](#parameter-imagesresourceid) | string | The resource id of the image. | + +### Parameter: `images.wellKnownImageName` + +The image to use from a well-known set of images made available to customers. + +- Required: Yes +- Type: string + +### Parameter: `images.aliases` + +List of aliases to reference the image by. + +- Required: No +- Type: array + +### Parameter: `images.buffer` + +The percentage of the buffer to be allocated to this image. + +- Required: No +- Type: string + +### Parameter: `images.resourceId` + +The resource id of the image. + +- Required: No +- Type: string + +### Parameter: `name` + +Name of the pool. It needs to be globally unique. + +- Required: Yes +- Type: string + +### Parameter: `organizationProfile` + +Defines the organization in which the pool will be used. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-organizationprofilekind) | string | Azure DevOps organization profile. | +| [`organizations`](#parameter-organizationprofileorganizations) | array | The list of Azure DevOps organizations the pool should be present in.. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`permissionProfile`](#parameter-organizationprofilepermissionprofile) | object | The type of permission which determines which accounts are admins on the Azure DevOps pool. | + +### Parameter: `organizationProfile.kind` + +Azure DevOps organization profile. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDevOps' + ] + ``` + +### Parameter: `organizationProfile.organizations` + +The list of Azure DevOps organizations the pool should be present in.. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`url`](#parameter-organizationprofileorganizationsurl) | string | The Azure DevOps organization URL in which the pool should be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`parallelism`](#parameter-organizationprofileorganizationsparallelism) | int | How many machines can be created at maximum in this organization out of the maximumConcurrency of the pool. | +| [`projects`](#parameter-organizationprofileorganizationsprojects) | array | List of projects in which the pool should be created. | + +### Parameter: `organizationProfile.organizations.url` + +The Azure DevOps organization URL in which the pool should be created. + +- Required: Yes +- Type: string + +### Parameter: `organizationProfile.organizations.parallelism` + +How many machines can be created at maximum in this organization out of the maximumConcurrency of the pool. + +- Required: No +- Type: int + +### Parameter: `organizationProfile.organizations.projects` + +List of projects in which the pool should be created. + +- Required: No +- Type: array + +### Parameter: `organizationProfile.permissionProfile` + +The type of permission which determines which accounts are admins on the Azure DevOps pool. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-organizationprofilepermissionprofilekind) | string | Determines who has admin permissions to the Azure DevOps pool. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groups`](#parameter-organizationprofilepermissionprofilegroups) | array | Group email addresses. | +| [`users`](#parameter-organizationprofilepermissionprofileusers) | array | User email addresses. | + +### Parameter: `organizationProfile.permissionProfile.kind` + +Determines who has admin permissions to the Azure DevOps pool. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'CreatorOnly' + 'Inherit' + 'SpecificAccounts' + ] + ``` + +### Parameter: `organizationProfile.permissionProfile.groups` + +Group email addresses. + +- Required: No +- Type: array + +### Parameter: `organizationProfile.permissionProfile.users` + +User email addresses. + +- Required: No +- Type: array + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +The geo-location where the resource lives. + +- 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: `managedIdentities` + +The managed service identities assigned to this resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + systemAssigned: true, + userAssignedResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myManagedIdentity' + ] + } + { + systemAssigned: true + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-managedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `managedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. + +- Required: No +- Type: bool + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `osProfile` + +The OS profile of the agents in the pool. + +- Required: No +- Type: object +- Default: + ```Bicep + { + logonType: 'Interactive' + secretsManagementSettings: { + keyExportable: false + observedCertificates: [] + } + } + ``` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`logonType`](#parameter-osprofilelogontype) | string | The logon type of the machine. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`secretsManagementSettings`](#parameter-osprofilesecretsmanagementsettings) | object | The secret management settings of the machines in the pool. | + +### Parameter: `osProfile.logonType` + +The logon type of the machine. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Interactive' + 'Service' + ] + ``` + +### Parameter: `osProfile.secretsManagementSettings` + +The secret management settings of the machines in the pool. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyExportable`](#parameter-osprofilesecretsmanagementsettingskeyexportable) | bool | The secret management settings of the machines in the pool. | +| [`observedCertificates`](#parameter-osprofilesecretsmanagementsettingsobservedcertificates) | array | The list of certificates to install on all machines in the pool. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`certificateStoreLocation`](#parameter-osprofilesecretsmanagementsettingscertificatestorelocation) | string | Where to store certificates on the machine. | + +### Parameter: `osProfile.secretsManagementSettings.keyExportable` + +The secret management settings of the machines in the pool. + +- Required: Yes +- Type: bool + +### Parameter: `osProfile.secretsManagementSettings.observedCertificates` + +The list of certificates to install on all machines in the pool. + +- Required: Yes +- Type: array + +### Parameter: `osProfile.secretsManagementSettings.certificateStoreLocation` + +Where to store certificates on the machine. + +- Required: No +- Type: string + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` + +**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. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`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.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- 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: `storageProfile` + +The storage profile of the machines in the pool. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dataDisks`](#parameter-storageprofiledatadisks) | array | A list of empty data disks to attach. | +| [`osDiskStorageAccountType`](#parameter-storageprofileosdiskstorageaccounttype) | string | The Azure SKU name of the machines in the pool. | + +### Parameter: `storageProfile.dataDisks` + +A list of empty data disks to attach. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`caching`](#parameter-storageprofiledatadiskscaching) | string | The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/. | +| [`diskSizeGiB`](#parameter-storageprofiledatadisksdisksizegib) | int | The initial disk size in gigabytes. | +| [`driveLetter`](#parameter-storageprofiledatadisksdriveletter) | string | The drive letter for the empty data disk. If not specified, it will be the first available letter. Letters A, C, D, and E are not allowed. | +| [`storageAccountType`](#parameter-storageprofiledatadisksstorageaccounttype) | string | The storage Account type to be used for the data disk. If omitted, the default is Standard_LRS. | + +### Parameter: `storageProfile.dataDisks.caching` + +The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'None' + 'ReadOnly' + 'ReadWrite' + ] + ``` + +### Parameter: `storageProfile.dataDisks.diskSizeGiB` + +The initial disk size in gigabytes. + +- Required: No +- Type: int + +### Parameter: `storageProfile.dataDisks.driveLetter` + +The drive letter for the empty data disk. If not specified, it will be the first available letter. Letters A, C, D, and E are not allowed. + +- Required: No +- Type: string + +### Parameter: `storageProfile.dataDisks.storageAccountType` + +The storage Account type to be used for the data disk. If omitted, the default is Standard_LRS. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Premium_LRS' + 'Premium_ZRS' + 'Standard_LRS' + 'StandardSSD_LRS' + 'StandardSSD_ZRS' + ] + ``` + +### Parameter: `storageProfile.osDiskStorageAccountType` + +The Azure SKU name of the machines in the pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Premium' + 'Standard' + 'StandardSSD' + ] + ``` + +### Parameter: `subnetResourceId` + +The subnet id on which to put all machines created in the pool. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the Managed DevOps Pool resource was deployed into. | +| `name` | string | The name of the Managed DevOps Pool. | +| `resourceGroupName` | string | The name of the resource group the Managed DevOps Pool resource was deployed into. | +| `resourceId` | string | The resource ID of the Managed DevOps Pool. | +| `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | + +## Notes + +The Managed DevOps Pool resource requires external permissions in Azure DevOps. Make sure that the deployment principal has permission in Azure DevOps: [Managed DevOps Pools - Verify Azure DevOps Permissions](https://learn.microsoft.com/en-us/azure/devops/managed-devops-pools/prerequisites?view=azure-devops&tabs=azure-portal#verify-azure-devops-permissions) + +## 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/dev-ops-infrastructure/pool/main.bicep b/avm/res/dev-ops-infrastructure/pool/main.bicep new file mode 100644 index 0000000000..af61e650fe --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/main.bicep @@ -0,0 +1,489 @@ +metadata name = 'Managed DevOps Pool' +metadata description = 'This module deploys the Managed DevOps Pool resource.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the pool. It needs to be globally unique.') +param name string + +@description('Required. The Azure SKU name of the machines in the pool.') +param fabricProfileSkuName string + +@minValue(1) +@maxValue(10000) +@description('Required. Defines how many resources can there be created at any given time.') +param concurrency int + +@description('Required. The VM images of the machines in the pool.') +param images imageType + +@description('Optional. The geo-location where the resource lives.') +param location string = resourceGroup().location + +@description('Required. The resource id of the DevCenter Project the pool belongs to.') +param devCenterProjectResourceId string + +@description('Optional. The subnet id on which to put all machines created in the pool.') +param subnetResourceId string? + +@description('Required. Defines how the machine will be handled once it executed a job.') +param agentProfile agentProfileType + +@description('Optional. The OS profile of the agents in the pool.') +param osProfile osProfileType = { + logonType: 'Interactive' + secretsManagementSettings: { + keyExportable: false + observedCertificates: [] + } +} + +@description('Optional. The storage profile of the machines in the pool.') +param storageProfile storageProfileType + +@description('Required. Defines the organization in which the pool will be used.') +param organizationProfile organizationProfileType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The managed service identities assigned to this resource.') +@metadata({ + example: ''' + { + systemAssigned: true, + userAssignedResourceIds: [ + '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myManagedIdentity' + ] + } + { + systemAssigned: true + } + ''' +}) +param managedIdentities managedIdentitiesType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.devopsinfrastructure-pool.${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 managedDevOpsPool 'Microsoft.DevOpsInfrastructure/pools@2024-04-04-preview' = { + name: name + location: location + tags: tags + identity: identity + properties: { + agentProfile: agentProfile + devCenterProjectResourceId: devCenterProjectResourceId + fabricProfile: { + sku: { + name: fabricProfileSkuName + } + networkProfile: !empty(subnetResourceId) + ? { + subnetId: subnetResourceId! + } + : null + osProfile: osProfile + storageProfile: storageProfile + kind: 'Vmss' + images: images + } + maximumConcurrency: concurrency + organizationProfile: organizationProfile + } +} + +resource managedDevOpsPool_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: managedDevOpsPool +} + +resource managedDevOpsPool_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + managedDevOpsPool.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + 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: managedDevOpsPool + } +] + +resource managedDevOpsPool_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: managedDevOpsPool + } +] + +@description('The name of the Managed DevOps Pool.') +output name string = managedDevOpsPool.name + +@description('The resource ID of the Managed DevOps Pool.') +output resourceId string = managedDevOpsPool.id + +@description('The name of the resource group the Managed DevOps Pool resource was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the Managed DevOps Pool resource was deployed into.') +output location string = managedDevOpsPool.location + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = managedDevOpsPool.?identity.?principalId + +type osProfileType = { + @description('Required. The logon type of the machine.') + logonType: ('Interactive' | 'Service') + + @description('Optional. The secret management settings of the machines in the pool.') + secretsManagementSettings: { + @description('Required. The secret management settings of the machines in the pool.') + keyExportable: bool + + @description('Required. The list of certificates to install on all machines in the pool.') + observedCertificates: string[] + + @description('Optional. Where to store certificates on the machine.') + certificateStoreLocation: string? + }? +} + +type storageProfileType = { + @description('Optional. The Azure SKU name of the machines in the pool.') + osDiskStorageAccountType: ('Premium' | 'StandardSSD' | 'Standard')? + + @description('Optional. A list of empty data disks to attach.') + dataDisks: { + @description('Optional. The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/.') + caching: ('None' | 'ReadOnly' | 'ReadWrite')? + + @description('Optional. The initial disk size in gigabytes.') + diskSizeGiB: int? + + @description('Optional. The drive letter for the empty data disk. If not specified, it will be the first available letter. Letters A, C, D, and E are not allowed.') + driveLetter: string? + + @description('Optional. The storage Account type to be used for the data disk. If omitted, the default is Standard_LRS.') + storageAccountType: ('Premium_LRS' | 'Premium_ZRS' | 'StandardSSD_LRS' | 'StandardSSD_ZRS' | 'Standard_LRS')? + }[]? +}? + +type imageType = { + @description('Optional. List of aliases to reference the image by.') + aliases: string[]? + + @description('Optional. The percentage of the buffer to be allocated to this image.') + buffer: string? + + @description('Required. The image to use from a well-known set of images made available to customers.') + wellKnownImageName: string + + @description('Optional. The resource id of the image.') + resourceId: string? +}[] + +type organizationProfileType = { + @description('Required. Azure DevOps organization profile.') + kind: 'AzureDevOps' + + @description('Optional. The type of permission which determines which accounts are admins on the Azure DevOps pool.') + permissionProfile: { + @description('Required. Determines who has admin permissions to the Azure DevOps pool.') + kind: 'CreatorOnly' | 'Inherit' | 'SpecificAccounts' + + @description('Optional. Group email addresses.') + groups: string[]? + + @description('Optional. User email addresses.') + users: string[]? + }? + + @description('Required. The list of Azure DevOps organizations the pool should be present in..') + organizations: { + @description('Required. The Azure DevOps organization URL in which the pool should be created.') + url: string + + @description('Optional. List of projects in which the pool should be created.') + projects: string[]? + + @description('Optional. How many machines can be created at maximum in this organization out of the maximumConcurrency of the pool.') + @minValue(1) + @maxValue(10000) + parallelism: int? + }[] +} + +type dataDiskType = { + @description('Optional. The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/.') + caching: ('None' | 'ReadOnly' | 'ReadWrite')? + + @description('Optional. The initial disk size in gigabytes.') + diskSizeGiB: int? + + @description('Optional. The drive letter for the empty data disk. If not specified, it will be the first available letter. Letters A, C, D, and E are not allowed.') + driveLetter: string? + + @description('Optional. The storage Account type to be used for the data disk. If omitted, the default is Standard_LRS.') + storageAccountType: ('Premium_LRS' | 'Premium_ZRS' | 'StandardSSD_LRS' | 'StandardSSD_ZRS' | 'Standard_LRS')? +}[]? + +type resourcePredictionsProfileAutomaticType = { + @description('Required. The stand-by agent scheme is determined based on historical demand.') + kind: 'Automatic' + + @description('Required. Determines the balance between cost and performance.') + predictionPreference: 'Balanced' | 'MostCostEffective' | 'MoreCostEffective' | 'MorePerformance' | 'BestPerformance' +} + +type resourcePredictionsProfileManualType = { + @description('Required. Customer provides the stand-by agent scheme.') + kind: 'Manual' +} + +type agentStatefulType = { + @description('Required. Stateful profile meaning that the machines will be returned to the pool after running a job.') + kind: 'Stateful' + + @description('Required. How long should stateful machines be kept around. The maximum is one week.') + maxAgentLifetime: string + + @description('Required. How long should the machine be kept around after it ran a workload when there are no stand-by agents. The maximum is one week.') + gracePeriodTimeSpan: string + + @description('Optional. Defines pool buffer/stand-by agents.') + resourcePredictions: object? + + @discriminator('kind') + @description('Optional. Determines how the stand-by scheme should be provided.') + resourcePredictionsProfile: (resourcePredictionsProfileAutomaticType | resourcePredictionsProfileManualType)? +} + +type agentStatelessType = { + @description('Required. Stateless profile meaning that the machines will be cleaned up after running a job.') + kind: 'Stateless' + + @description('Optional. Defines pool buffer/stand-by agents.') + resourcePredictions: { + @description('Required. The time zone in which the daysData is provided. To see the list of available time zones, see: https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones?view=windows-11#time-zones or via PowerShell command `(Get-TimeZone -ListAvailable).StandardName`.') + timeZone: string + + @description('Optional. The number of agents needed at a specific time.') + @metadata({ + example: ''' + [ + { // Monday + '09:00': 5 + '22:00': 0 + } + {} // Tuesday + {} // Wednesday + {} // Thursday + { // Friday + '09:00': 5 + '22:00': 0 + } + {} // Saturday + {} // Sunday + ] + ''' + }) + daysData: object[]? + }? + + @discriminator('kind') + @description('Optional. Determines how the stand-by scheme should be provided.') + resourcePredictionsProfile: (resourcePredictionsProfileAutomaticType | resourcePredictionsProfileManualType)? +} + +@discriminator('kind') +type agentProfileType = agentStatefulType | agentStatelessType + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @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? +}[]? + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +}? diff --git a/avm/res/dev-ops-infrastructure/pool/main.json b/avm/res/dev-ops-infrastructure/pool/main.json new file mode 100644 index 0000000000..689ef6eb8c --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/main.json @@ -0,0 +1,1012 @@ +{ + "$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.30.23.60470", + "templateHash": "3502193398932835678" + }, + "name": "Managed DevOps Pool", + "description": "This module deploys the Managed DevOps Pool resource.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "osProfileType": { + "type": "object", + "properties": { + "logonType": { + "type": "string", + "allowedValues": [ + "Interactive", + "Service" + ], + "metadata": { + "description": "Required. The logon type of the machine." + } + }, + "secretsManagementSettings": { + "type": "object", + "properties": { + "keyExportable": { + "type": "bool", + "metadata": { + "description": "Required. The secret management settings of the machines in the pool." + } + }, + "observedCertificates": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of certificates to install on all machines in the pool." + } + }, + "certificateStoreLocation": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Where to store certificates on the machine." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The secret management settings of the machines in the pool." + } + } + } + }, + "storageProfileType": { + "type": "object", + "properties": { + "osDiskStorageAccountType": { + "type": "string", + "allowedValues": [ + "Premium", + "Standard", + "StandardSSD" + ], + "nullable": true, + "metadata": { + "description": "Optional. The Azure SKU name of the machines in the pool." + } + }, + "dataDisks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/." + } + }, + "diskSizeGiB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The initial disk size in gigabytes." + } + }, + "driveLetter": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The drive letter for the empty data disk. If not specified, it will be the first available letter. Letters A, C, D, and E are not allowed." + } + }, + "storageAccountType": { + "type": "string", + "allowedValues": [ + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. The storage Account type to be used for the data disk. If omitted, the default is Standard_LRS." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of empty data disks to attach." + } + } + }, + "nullable": true + }, + "imageType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "aliases": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of aliases to reference the image by." + } + }, + "buffer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The percentage of the buffer to be allocated to this image." + } + }, + "wellKnownImageName": { + "type": "string", + "metadata": { + "description": "Required. The image to use from a well-known set of images made available to customers." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource id of the image." + } + } + } + } + }, + "organizationProfileType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "AzureDevOps" + ], + "metadata": { + "description": "Required. Azure DevOps organization profile." + } + }, + "permissionProfile": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "CreatorOnly", + "Inherit", + "SpecificAccounts" + ], + "metadata": { + "description": "Required. Determines who has admin permissions to the Azure DevOps pool." + } + }, + "groups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Group email addresses." + } + }, + "users": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. User email addresses." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The type of permission which determines which accounts are admins on the Azure DevOps pool." + } + }, + "organizations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string", + "metadata": { + "description": "Required. The Azure DevOps organization URL in which the pool should be created." + } + }, + "projects": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of projects in which the pool should be created." + } + }, + "parallelism": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10000, + "metadata": { + "description": "Optional. How many machines can be created at maximum in this organization out of the maximumConcurrency of the pool." + } + } + } + }, + "metadata": { + "description": "Required. The list of Azure DevOps organizations the pool should be present in.." + } + } + } + }, + "dataDiskType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "caching": { + "type": "string", + "allowedValues": [ + "None", + "ReadOnly", + "ReadWrite" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/." + } + }, + "diskSizeGiB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The initial disk size in gigabytes." + } + }, + "driveLetter": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The drive letter for the empty data disk. If not specified, it will be the first available letter. Letters A, C, D, and E are not allowed." + } + }, + "storageAccountType": { + "type": "string", + "allowedValues": [ + "Premium_LRS", + "Premium_ZRS", + "StandardSSD_LRS", + "StandardSSD_ZRS", + "Standard_LRS" + ], + "nullable": true, + "metadata": { + "description": "Optional. The storage Account type to be used for the data disk. If omitted, the default is Standard_LRS." + } + } + } + }, + "nullable": true + }, + "resourcePredictionsProfileAutomaticType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Automatic" + ], + "metadata": { + "description": "Required. The stand-by agent scheme is determined based on historical demand." + } + }, + "predictionPreference": { + "type": "string", + "allowedValues": [ + "Balanced", + "BestPerformance", + "MoreCostEffective", + "MorePerformance", + "MostCostEffective" + ], + "metadata": { + "description": "Required. Determines the balance between cost and performance." + } + } + } + }, + "resourcePredictionsProfileManualType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Manual" + ], + "metadata": { + "description": "Required. Customer provides the stand-by agent scheme." + } + } + } + }, + "agentStatefulType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Stateful" + ], + "metadata": { + "description": "Required. Stateful profile meaning that the machines will be returned to the pool after running a job." + } + }, + "maxAgentLifetime": { + "type": "string", + "metadata": { + "description": "Required. How long should stateful machines be kept around. The maximum is one week." + } + }, + "gracePeriodTimeSpan": { + "type": "string", + "metadata": { + "description": "Required. How long should the machine be kept around after it ran a workload when there are no stand-by agents. The maximum is one week." + } + }, + "resourcePredictions": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Defines pool buffer/stand-by agents." + } + }, + "resourcePredictionsProfile": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Automatic": { + "$ref": "#/definitions/resourcePredictionsProfileAutomaticType" + }, + "Manual": { + "$ref": "#/definitions/resourcePredictionsProfileManualType" + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Determines how the stand-by scheme should be provided." + } + } + } + }, + "agentStatelessType": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "allowedValues": [ + "Stateless" + ], + "metadata": { + "description": "Required. Stateless profile meaning that the machines will be cleaned up after running a job." + } + }, + "resourcePredictions": { + "type": "object", + "properties": { + "timeZone": { + "type": "string", + "metadata": { + "description": "Required. The time zone in which the daysData is provided. To see the list of available time zones, see: https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-time-zones?view=windows-11#time-zones or via PowerShell command `(Get-TimeZone -ListAvailable).StandardName`." + } + }, + "daysData": { + "type": "array", + "items": { + "type": "object" + }, + "nullable": true, + "metadata": { + "example": " [\n { // Monday\n '09:00': 5\n '22:00': 0\n }\n {} // Tuesday\n {} // Wednesday\n {} // Thursday\n { // Friday\n '09:00': 5\n '22:00': 0\n }\n {} // Saturday\n {} // Sunday\n ]\n ", + "description": "Optional. The number of agents needed at a specific time." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Defines pool buffer/stand-by agents." + } + }, + "resourcePredictionsProfile": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Automatic": { + "$ref": "#/definitions/resourcePredictionsProfileAutomaticType" + }, + "Manual": { + "$ref": "#/definitions/resourcePredictionsProfileManualType" + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Determines how the stand-by scheme should be provided." + } + } + } + }, + "agentProfileType": { + "type": "object", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Stateful": { + "$ref": "#/definitions/agentStatefulType" + }, + "Stateless": { + "$ref": "#/definitions/agentStatelessType" + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the pool. It needs to be globally unique." + } + }, + "fabricProfileSkuName": { + "type": "string", + "metadata": { + "description": "Required. The Azure SKU name of the machines in the pool." + } + }, + "concurrency": { + "type": "int", + "minValue": 1, + "maxValue": 10000, + "metadata": { + "description": "Required. Defines how many resources can there be created at any given time." + } + }, + "images": { + "$ref": "#/definitions/imageType", + "metadata": { + "description": "Required. The VM images of the machines in the pool." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The geo-location where the resource lives." + } + }, + "devCenterProjectResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the DevCenter Project the pool belongs to." + } + }, + "subnetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subnet id on which to put all machines created in the pool." + } + }, + "agentProfile": { + "$ref": "#/definitions/agentProfileType", + "metadata": { + "description": "Required. Defines how the machine will be handled once it executed a job." + } + }, + "osProfile": { + "$ref": "#/definitions/osProfileType", + "defaultValue": { + "logonType": "Interactive", + "secretsManagementSettings": { + "keyExportable": false, + "observedCertificates": [] + } + }, + "metadata": { + "description": "Optional. The OS profile of the agents in the pool." + } + }, + "storageProfile": { + "$ref": "#/definitions/storageProfileType", + "metadata": { + "description": "Optional. The storage profile of the machines in the pool." + } + }, + "organizationProfile": { + "$ref": "#/definitions/organizationProfileType", + "metadata": { + "description": "Required. Defines the organization in which the pool will be used." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "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." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "example": " {\n systemAssigned: true,\n userAssignedResourceIds: [\n '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myManagedIdentity'\n ]\n }\n {\n systemAssigned: true\n }\n ", + "description": "Optional. The managed service identities assigned to this resource." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "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(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', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.devopsinfrastructure-pool.{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" + } + } + } + } + }, + "managedDevOpsPool": { + "type": "Microsoft.DevOpsInfrastructure/pools", + "apiVersion": "2024-04-04-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "agentProfile": "[parameters('agentProfile')]", + "devCenterProjectResourceId": "[parameters('devCenterProjectResourceId')]", + "fabricProfile": { + "sku": { + "name": "[parameters('fabricProfileSkuName')]" + }, + "networkProfile": "[if(not(empty(parameters('subnetResourceId'))), createObject('subnetId', parameters('subnetResourceId')), null())]", + "osProfile": "[parameters('osProfile')]", + "storageProfile": "[parameters('storageProfile')]", + "kind": "Vmss", + "images": "[parameters('images')]" + }, + "maximumConcurrency": "[parameters('concurrency')]", + "organizationProfile": "[parameters('organizationProfile')]" + } + }, + "managedDevOpsPool_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.DevOpsInfrastructure/pools/{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": [ + "managedDevOpsPool" + ] + }, + "managedDevOpsPool_roleAssignments": { + "copy": { + "name": "managedDevOpsPool_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DevOpsInfrastructure/pools/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DevOpsInfrastructure/pools', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedDevOpsPool" + ] + }, + "managedDevOpsPool_diagnosticSettings": { + "copy": { + "name": "managedDevOpsPool_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DevOpsInfrastructure/pools/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "managedDevOpsPool" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Managed DevOps Pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Managed DevOps Pool." + }, + "value": "[resourceId('Microsoft.DevOpsInfrastructure/pools', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Managed DevOps Pool resource was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the Managed DevOps Pool resource was deployed into." + }, + "value": "[reference('managedDevOpsPool', '2024-04-04-preview', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[tryGet(tryGet(reference('managedDevOpsPool', '2024-04-04-preview', 'full'), 'identity'), 'principalId')]" + } + } +} \ No newline at end of file diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/dependencies.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..367ae50af8 --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,27 @@ +@description('Required. The name of the Dev Center.') +param devCenterName string + +@description('Required. The name of the Dev Center Project.') +param devCenterProjectName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource devCenter 'Microsoft.DevCenter/devcenters@2024-02-01' = { + name: devCenterName + location: location +} + +resource devCenterProject 'Microsoft.DevCenter/projects@2024-02-01' = { + name: devCenterProjectName + location: location + properties: { + devCenterId: devCenter.id + } +} + +@description('The resource ID of the created DevCenter.') +output devCenterResourceId string = devCenter.id + +@description('The resource ID of the created DevCenter Project.') +output devCenterProjectResourceId string = devCenterProject.id diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..45332f3a95 --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,79 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dev-ops-infrastructure.pool-${serviceShort}-rg' + +@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 = 'mdpmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Required. Name of the Azure DevOps organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') +@secure() +param azureDevOpsOrganizationName string = '' + +// The Managed DevOps Pools resource is not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + devCenterName: 'dep-${namePrefix}-dc-${serviceShort}' + devCenterProjectName: 'dep-${namePrefix}-dcp-${serviceShort}' + } +} + +// ================= // +// General resources // +// ================= // +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + agentProfile: { + kind: 'Stateless' + } + concurrency: 1 + devCenterProjectResourceId: nestedDependencies.outputs.devCenterProjectResourceId + images: [ + { + wellKnownImageName: 'windows-2022/latest' + } + ] + fabricProfileSkuName: 'Standard_DS2_v2' + organizationProfile: { + kind: 'AzureDevOps' + organizations: [ + { + url: 'https://dev.azure.com/${azureDevOpsOrganizationName}' + } + ] + } + } + } +] diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/dependencies.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..11333fc560 --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/dependencies.bicep @@ -0,0 +1,89 @@ +@description('Required. The name of the Dev Center.') +param devCenterName string + +@description('Required. The name of the Dev Center Project.') +param devCenterProjectName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the virtual network to create.') +param virtualNetworkName string + +@description('Required. The object ID of the Entra ID-provided DevOpsInfrastructure principal.') +param devOpsInfrastructureObjectID string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '192.168.1.0' + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource devCenter 'Microsoft.DevCenter/devcenters@2024-02-01' = { + name: devCenterName + location: location +} + +resource devCenterProject 'Microsoft.DevCenter/projects@2024-02-01' = { + name: devCenterProjectName + location: location + properties: { + devCenterId: devCenter.id + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + cidrSubnet(addressPrefix, 24, 0) + ] + } + subnets: [ + { + name: 'default' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + delegations: [ + { + name: 'Microsoft.DevOpsInfrastructure/pools' + properties: { + serviceName: 'Microsoft.DevOpsInfrastructure/pools' + } + } + ] + } + } + ] + } +} + +// Network Contributor role assignment +resource roleAssignments 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { + name: guid(subscription().subscriptionId, 'DevOpsInfrastructure', 'Network Contributor', 'max') + properties: { + principalId: devOpsInfrastructureObjectID // DevOpsInfrastructure service principal + #disable-next-line use-resource-id-functions + roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7' + principalType: 'ServicePrincipal' + } + scope: virtualNetwork +} + +@description('The resource ID of the created DevCenter.') +output devCenterResourceId string = devCenter.id + +@description('The resource ID of the created DevCenter Project.') +output devCenterProjectResourceId string = devCenterProject.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created subnet.') +output subnetResourceId string = first(virtualNetwork.properties.subnets)!.id diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/main.test.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..09b40200e5 --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/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 = 'dep-${namePrefix}-dev-ops-infrastructure.pool-${serviceShort}-rg' + +@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 = 'mdpmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Required. Name of the Azure DevOps organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') +@secure() +param azureDevOpsOrganizationName string = '' + +@description('Required. Name of the Azure DevOps Max Project. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsProjectName\'.') +@secure() +param azureDevOpsProjectName string = '' + +@description('Required. The object ID of the Entra ID-provided DevOpsInfrastructure principal. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-DevOpsInfrastructureObjectID\'.') +@secure() +param devOpsInfrastructureObjectID string = '' + +// The Managed DevOps Pools resource is not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + devCenterName: 'dep-${namePrefix}-dc-${serviceShort}' + devCenterProjectName: 'dep-${namePrefix}-dcp-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + devOpsInfrastructureObjectID: devOpsInfrastructureObjectID + } +} + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + agentProfile: { + kind: 'Stateless' + resourcePredictions: { + timeZone: 'Central Europe Standard Time' + daysData: [ + // Monday + { + '09:00:00': 1 + '17:00:00': 0 + } + // Tuesday + {} + // Wednesday + {} + // Thursday + {} + // Friday + { + '09:00:00': 1 + '17:00:00': 0 + } + // Saturday + {} + // Sunday + {} + ] + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } + } + concurrency: 1 + devCenterProjectResourceId: nestedDependencies.outputs.devCenterProjectResourceId + images: [ + { + aliases: [ + 'windows-2022' + ] + buffer: '*' + wellKnownImageName: 'windows-2022/latest' + } + ] + fabricProfileSkuName: 'Standard_D2_v2' + organizationProfile: { + kind: 'AzureDevOps' + organizations: [ + { + url: 'https://dev.azure.com/${azureDevOpsOrganizationName}' + parallelism: 1 + projects: [ + azureDevOpsProjectName + ] + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } + } + storageProfile: { + osDiskStorageAccountType: 'Standard' + dataDisks: [ + { + caching: 'ReadWrite' + diskSizeGiB: 100 + driveLetter: 'B' + storageAccountType: 'Standard_LRS' + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + roleAssignments: [ + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + } +] diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..0afb813bac --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,89 @@ +@description('Required. The name of the Dev Center.') +param devCenterName string + +@description('Required. The name of the Dev Center Project.') +param devCenterProjectName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the virtual network to create.') +param virtualNetworkName string + +@description('Required. The object ID of the Entra ID-provided DevOpsInfrastructure principal.') +param devOpsInfrastructureObjectID string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +var addressPrefix = '192.168.1.0' + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource devCenter 'Microsoft.DevCenter/devcenters@2024-02-01' = { + name: devCenterName + location: location +} + +resource devCenterProject 'Microsoft.DevCenter/projects@2024-02-01' = { + name: devCenterProjectName + location: location + properties: { + devCenterId: devCenter.id + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + cidrSubnet(addressPrefix, 24, 0) + ] + } + subnets: [ + { + name: 'default' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + delegations: [ + { + name: 'Microsoft.DevOpsInfrastructure/pools' + properties: { + serviceName: 'Microsoft.DevOpsInfrastructure/pools' + } + } + ] + } + } + ] + } +} + +// Network Contributor role assignment +resource roleAssignments 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { + name: guid(subscription().subscriptionId, 'DevOpsInfrastructure', 'Network Contributor', 'waf') + properties: { + principalId: devOpsInfrastructureObjectID // DevOpsInfrastructure service principal + #disable-next-line use-resource-id-functions + roleDefinitionId: '/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7' + principalType: 'ServicePrincipal' + } + scope: virtualNetwork +} + +@description('The resource ID of the created DevCenter.') +output devCenterResourceId string = devCenter.id + +@description('The resource ID of the created DevCenter Project.') +output devCenterProjectResourceId string = devCenterProject.id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created subnet.') +output subnetResourceId string = first(virtualNetwork.properties.subnets)!.id diff --git a/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep b/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..20a04a3900 --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,128 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-dev-ops-infrastructure.pool-${serviceShort}-rg' + +@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 = 'mdpwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Required. Name of the Azure DevOps organization. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsOrganizationName\'.') +@secure() +param azureDevOpsOrganizationName string = '' + +@description('Required. Name of the Azure DevOps WAF Project. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-AzureDevOpsProjectName\'.') +@secure() +param azureDevOpsProjectName string = '' + +@description('Required. The object ID of the Entra ID-provided DevOpsInfrastructure principal. This value is tenant-specific and must be stored in the CI Key Vault in a secret named \'CI-DevOpsInfrastructureObjectID\'.') +@secure() +param devOpsInfrastructureObjectID string = '' + +// The Managed DevOps Pools resource is not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + devCenterName: 'dep-${namePrefix}-dc-${serviceShort}' + devCenterProjectName: 'dep-${namePrefix}-dcp-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + devOpsInfrastructureObjectID: devOpsInfrastructureObjectID + } +} + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + agentProfile: { + kind: 'Stateless' + resourcePredictions: { + timeZone: 'Central Europe Standard Time' + daysData: [ + // Monday + { + '09:00:00': 1 + '17:00:00': 0 + } + // Tuesday + {} + // Wednesday + {} + // Thursday + {} + // Friday + { + '09:00:00': 1 + '17:00:00': 0 + } + // Saturday + {} + // Sunday + {} + ] + } + resourcePredictionsProfile: { + kind: 'Automatic' + predictionPreference: 'Balanced' + } + } + concurrency: 1 + devCenterProjectResourceId: nestedDependencies.outputs.devCenterProjectResourceId + images: [ + { + wellKnownImageName: 'windows-2022/latest' + } + ] + fabricProfileSkuName: 'Standard_D2_v2' + subnetResourceId: nestedDependencies.outputs.subnetResourceId + organizationProfile: { + kind: 'AzureDevOps' + organizations: [ + { + url: 'https://dev.azure.com/${azureDevOpsOrganizationName}' + projects: [ + azureDevOpsProjectName + ] + parallelism: 1 + } + ] + permissionProfile: { + kind: 'CreatorOnly' + } + } + } + } +] diff --git a/avm/res/dev-ops-infrastructure/pool/version.json b/avm/res/dev-ops-infrastructure/pool/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/dev-ops-infrastructure/pool/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/dev-test-lab/lab/README.md b/avm/res/dev-test-lab/lab/README.md index 22a277da2a..4c3db963d8 100644 --- a/avm/res/dev-test-lab/lab/README.md +++ b/avm/res/dev-test-lab/lab/README.md @@ -1590,6 +1590,15 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DevTest Labs User'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Virtual Machine Contributor'` **Required parameters** diff --git a/avm/res/digital-twins/digital-twins-instance/README.md b/avm/res/digital-twins/digital-twins-instance/README.md index 8dc8fc0cd8..1cb5feb1f6 100644 --- a/avm/res/digital-twins/digital-twins-instance/README.md +++ b/avm/res/digital-twins/digital-twins-instance/README.md @@ -59,7 +59,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    -via JSON Parameter file +via JSON parameters file ```json { @@ -76,6 +76,19 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +param name = 'dtdimin001' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -192,7 +205,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    -via JSON Parameter file +via JSON parameters file ```json { @@ -322,6 +335,112 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +// Required parameters +param name = 'dtdmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventGridEndpoints = [ + { + eventGridDomainId: '' + topicEndpoint: '' + } +] +param eventHubEndpoints = [ + { + authenticationType: 'IdentityBased' + endpointUri: '' + entityPath: '' + managedIdentities: { + userAssignedResourceId: '' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param serviceBusEndpoints = [ + { + authenticationType: 'IdentityBased' + endpointUri: '' + entityPath: '' + managedIdentities: { + userAssignedResourceId: '' + } + name: 'ServiceBusPrimary' + } + { + authenticationType: 'IdentityBased' + endpointUri: '' + entityPath: '' + managedIdentities: { + systemAssigned: true + } + name: 'ServiceBusSeconday' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using private endpoint parameter set_ This instance deploys the module with idempotancy tests for private endpoints. @@ -362,7 +481,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    -via JSON Parameter file +via JSON parameters file ```json { @@ -400,6 +519,36 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +// Required parameters +param name = 'dtdpep001' +// Non-required parameters +param location = '' +param privateEndpoints = [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + } +] +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -439,7 +588,7 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    -via JSON Parameter file +via JSON parameters file ```json { @@ -478,6 +627,35 @@ module digitalTwinsInstance 'br/public:avm/res/digital-twins/digital-twins-insta

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/digital-twins/digital-twins-instance:' + +// Required parameters +param name = 'dtdiwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -996,6 +1174,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1115,6 +1304,14 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' - Required: No - Type: array +- Roles configurable by name: + - `'Azure Digital Twins Data Owner'` + - `'Azure Digital Twins Data Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index 24654fcc7f..44848ebee3 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -85,7 +85,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -117,6 +117,28 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'analytical' +// Non-required parameters +param enableAnalyticalStorage = true +param location = '' +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
    +

    + ### Example 2: _Using bounded consistency_ This instance deploys the module specifying a default consistency level. @@ -151,7 +173,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -189,6 +211,30 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'bounded' +// Non-required parameters +param defaultConsistencyLevel = 'BoundedStaleness' +param location = '' +param maxIntervalInSeconds = 600 +param maxStalenessPrefix = 200000 +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
    +

    + ### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -215,7 +261,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -237,6 +283,22 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 4: _Gremlin Database_ This instance deploys the module with a Gremlin Database. @@ -367,7 +429,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -507,6 +569,126 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddagrm002' +// Non-required parameters +param capabilitiesToAdd = [ + 'EnableGremlin' +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gremlinDatabases = [ + { + graphs: [ + { + indexingPolicy: { + automatic: true + } + name: 'car_collection' + partitionKeyPaths: [ + '/car_id' + ] + } + { + indexingPolicy: { + automatic: true + } + name: 'truck_collection' + partitionKeyPaths: [ + '/truck_id' + ] + } + ] + name: 'gdb-dddagrm-001' + throughput: 10000 + } + { + graphs: [ + { + indexingPolicy: { + automatic: true + } + name: 'bike_collection' + partitionKeyPaths: [ + '/bike_id' + ] + } + { + indexingPolicy: { + automatic: true + } + name: 'bicycle_collection' + partitionKeyPaths: [ + '/bicycle_id' + ] + } + ] + name: 'gdb-dddagrm-002' + } +] +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } + { + failoverPriority: 1 + isZoneRedundant: false + locationName: '' + } +] +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 5: _Deploying with a key vault reference to save secrets_ This instance deploys the module saving all its secrets in a key vault. @@ -544,7 +726,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -579,6 +761,33 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'kv-ref' +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + keyVaultResourceId: '' + primaryReadonlyConnectionStringSecretName: 'primaryReadonlyConnectionString' + primaryReadOnlyKeySecretName: 'primaryReadOnlyKey' + primaryWriteConnectionStringSecretName: 'primaryWriteConnectionString' + primaryWriteKeySecretName: 'primaryWriteKey' + secondaryReadonlyConnectionStringSecretName: 'secondaryReadonlyConnectionString' + secondaryReadonlyKeySecretName: 'secondaryReadonlyKey' + secondaryWriteConnectionStringSecretName: 'secondaryWriteConnectionString' + secondaryWriteKeySecretName: 'secondaryWriteKey' +} +``` + +
    +

    + ### Example 6: _Deploying with Managed identities_ This instance deploys the module with an system and user assigned managed identity. @@ -629,7 +838,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -679,6 +888,46 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'user-mi' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
    +

    + ### Example 7: _Mongo Database_ This instance deploys the module with a Mongo Database. @@ -943,7 +1192,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1215,6 +1464,260 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddamng001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } + { + failoverPriority: 1 + isZoneRedundant: false + locationName: '' + } +] +param managedIdentities = { + systemAssigned: true +} +param mongodbDatabases = [ + { + collections: [ + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'car_id' + 'car_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'car_collection' + shardKey: { + car_id: 'Hash' + } + throughput: 600 + } + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'truck_id' + 'truck_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'truck_collection' + shardKey: { + truck_id: 'Hash' + } + } + ] + name: 'mdb-dddamng-001' + throughput: 800 + } + { + collections: [ + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'bike_id' + 'bike_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'bike_collection' + shardKey: { + bike_id: 'Hash' + } + } + { + indexes: [ + { + key: { + keys: [ + '_id' + ] + } + } + { + key: { + keys: [ + '$**' + ] + } + } + { + key: { + keys: [ + 'bicycle_id' + 'bicycle_model' + ] + } + options: { + unique: true + } + } + { + key: { + keys: [ + '_ts' + ] + } + options: { + expireAfterSeconds: 2629746 + } + } + ] + name: 'bicycle_collection' + shardKey: { + bicycle_id: 'Hash' + } + } + ] + name: 'mdb-dddamng-002' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 8: _Deploying multiple regions_ This instance deploys the module in multiple regions with configs specific of multi region scenarios. @@ -1264,7 +1767,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1325,6 +1828,45 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'multi-region' +// Non-required parameters +param automaticFailover = false +param backupIntervalInMinutes = 300 +param backupPolicyType = 'Periodic' +param backupRetentionIntervalInHours = 16 +param backupStorageRedundancy = 'Zone' +param enableMultipleWriteLocations = true +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: true + locationName: '' + } + { + failoverPriority: 1 + isZoneRedundant: true + locationName: '' + } +] +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
    +

    + ### Example 9: _Plain_ This instance deploys the module without a Database. @@ -1368,7 +1910,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1421,6 +1963,39 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddapln001' +// Non-required parameters +param backupPolicyContinuousTier = 'Continuous7Days' +param backupPolicyType = 'Continuous' +param defaultConsistencyLevel = 'ConsistentPrefix' +param disableKeyBasedMetadataWriteAccess = true +param disableLocalAuth = true +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } +] +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
    +

    + ### Example 10: _Public network restricted access with ACL_ This instance deploys the module with public network access enabled but restricted to IPs, CIDRS or subnets. @@ -1465,7 +2040,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1509,6 +2084,40 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddapres001' +// Non-required parameters +param location = '' +param networkRestrictions = { + ipRules: [ + '79.0.0.0' + '80.0.0.0' + ] + networkAclBypass: 'AzureServices' + publicNetworkAccess: 'Enabled' + virtualNetworkRules: [ + { + subnetResourceId: '' + } + ] +} +param sqlDatabases = [ + { + name: 'no-containers-specified' + } +] +``` + +
    +

    + ### Example 11: _Deploying with a sql role definision and assignment_ This instance deploys the module with sql role definision and assignment @@ -1543,7 +2152,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1577,6 +2186,30 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'role-ref' +// Non-required parameters +param location = '' +param sqlRoleAssignmentsPrincipalIds = [ + '' +] +param sqlRoleDefinitions = [ + { + name: 'cosmos-sql-role-test' + } +] +``` + +
    +

    + ### Example 12: _SQL Database_ This instance deploys the module with a SQL Database. @@ -1861,7 +2494,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2147,6 +2780,280 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddasql001' +// Non-required parameters +param enableAnalyticalStorage = true +param location = '' +param locations = [ + { + failoverPriority: 0 + isZoneRedundant: false + locationName: '' + } +] +param sqlDatabases = [ + { + containers: [ + { + analyticalStorageTtl: 0 + conflictResolutionPolicy: { + conflictResolutionPath: '/myCustomId' + mode: 'LastWriterWins' + } + defaultTtl: 1000 + indexingPolicy: { + automatic: true + } + kind: 'Hash' + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + throughput: 600 + uniqueKeyPolicyKeys: [ + { + paths: [ + '/firstName' + ] + } + { + paths: [ + '/lastName' + ] + } + ] + } + ] + name: 'all-configs-specified' + } + { + containers: [ + { + indexingPolicy: { + automatic: true + } + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'automatic-indexing-policy' + } + { + containers: [ + { + conflictResolutionPolicy: { + conflictResolutionPath: '/myCustomId' + mode: 'LastWriterWins' + } + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'last-writer-conflict-resolution-policy' + } + { + containers: [ + { + analyticalStorageTtl: 1000 + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'fixed-analytical-ttl' + } + { + containers: [ + { + analyticalStorageTtl: -1 + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'infinite-analytical-ttl' + } + { + containers: [ + { + defaultTtl: 1000 + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'document-ttl' + } + { + containers: [ + { + name: 'container-001' + paths: [ + '/myPartitionKey' + ] + uniqueKeyPolicyKeys: [ + { + paths: [ + '/firstName' + ] + } + { + paths: [ + '/lastName' + ] + } + ] + } + ] + name: 'unique-key-policy' + } + { + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + throughput: 500 + } + ] + name: 'db-and-container-fixed-throughput-level' + throughput: 500 + } + { + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + throughput: 500 + } + ] + name: 'container-fixed-throughput-level' + } + { + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'database-fixed-throughput-level' + throughput: 500 + } + { + autoscaleSettingsMaxThroughput: 1000 + containers: [ + { + autoscaleSettingsMaxThroughput: 1000 + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'db-and-container-autoscale-level' + } + { + containers: [ + { + autoscaleSettingsMaxThroughput: 1000 + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'container-autoscale-level' + } + { + autoscaleSettingsMaxThroughput: 1000 + containers: [ + { + name: 'container-003' + paths: [ + '/myPartitionKey' + ] + } + ] + name: 'database-autoscale-level' + } + { + containers: [ + { + kind: 'MultiHash' + name: 'container-001' + paths: [ + '/myPartitionKey1' + '/myPartitionKey2' + '/myPartitionKey3' + ] + } + { + kind: 'MultiHash' + name: 'container-002' + paths: [ + 'myPartitionKey1' + 'myPartitionKey2' + 'myPartitionKey3' + ] + } + { + kind: 'Hash' + name: 'container-003' + paths: [ + '/myPartitionKey1' + ] + } + { + kind: 'Hash' + name: 'container-004' + paths: [ + 'myPartitionKey1' + ] + } + { + kind: 'Hash' + name: 'container-005' + paths: [ + 'myPartitionKey1' + ] + version: 2 + } + ] + name: 'all-partition-key-types' + } + { + containers: [] + name: 'empty-containers-array' + } + { + name: 'no-containers-specified' + } +] +``` + +
    +

    + ### Example 13: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -2223,7 +3130,7 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2307,6 +3214,72 @@ module databaseAccount 'br/public:avm/res/document-db/database-account:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/database-account:' + +// Required parameters +param name = 'dddawaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableKeyBasedMetadataWriteAccess = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Sql' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sqlDatabases = [ + { + containers: [ + { + kind: 'Hash' + name: 'container-001' + paths: [ + '/myPartitionKey1' + ] + } + ] + name: 'sql-dddawaf-001' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -3189,6 +4162,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -3293,6 +4277,17 @@ Array of role assignment objects that contain the 'roleDefinitionIdOrName' and ' - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Cosmos DB Account Reader Role'` + - `'Cosmos DB Operator'` + - `'CosmosBackupOperator'` + - `'CosmosRestoreOperator'` + - `'DocumentDB Account Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/document-db/mongo-cluster/README.md b/avm/res/document-db/mongo-cluster/README.md new file mode 100644 index 0000000000..2ebb5f8479 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/README.md @@ -0,0 +1,1555 @@ +# Azure Cosmos DB MongoDB vCore cluster `[Microsoft.DocumentDB/mongoClusters]` + +This module deploys a Azure Cosmos DB MongoDB vCore cluster. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## 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.DocumentDB/mongoClusters` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters) | +| `Microsoft.DocumentDB/mongoClusters/firewallRules` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters/firewallRules) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## 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/document-db/mongo-cluster:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Deploying with a key vault reference to save secrets](#example-2-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin001' + administratorLoginPassword: '' + name: 'ddmcdefmin001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin001" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "ddmcdefmin001" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin001' +param administratorLoginPassword = '' +param name = 'ddmcdefmin001' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 2: _Deploying with a key vault reference to save secrets_ + +This instance deploys the module saving its secrets in a key vault. + + +

    + +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin002' + administratorLoginPassword: '' + name: 'kv-ref' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + secretsExportConfiguration: { + connectionStringSecretName: 'connectionString' + keyVaultResourceId: '' + } + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin002" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "kv-ref" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "connectionStringSecretName": "connectionString", + "keyVaultResourceId": "" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin002' +param administratorLoginPassword = '' +param name = 'kv-ref' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + connectionStringSecretName: 'connectionString' + keyVaultResourceId: '' +} +``` + +
    +

    + +### Example 3: _Using large parameter set_ + +This instance deploys the module with the maximum set of required parameters. + + +

    + +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin003' + administratorLoginPassword: '' + name: 'ddmcmax001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + createMode: 'Default' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + highAvailabilityMode: false + location: '' + networkAcls: { + allowAllIPs: true + allowAzureIPs: true + customRules: [ + { + endIpAddress: '5.6.7.8' + firewallRuleName: 'allow-1.2.3.4-to-5.6.7.8' + startIpAddress: '1.2.3.4' + } + ] + } + nodeType: 'Shard' + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } + ] + roleAssignments: [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin003" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "ddmcmax001" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "createMode": { + "value": "Default" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "highAvailabilityMode": { + "value": false + }, + "location": { + "value": "" + }, + "networkAcls": { + "value": { + "allowAllIPs": true, + "allowAzureIPs": true, + "customRules": [ + { + "endIpAddress": "5.6.7.8", + "firewallRuleName": "allow-1.2.3.4-to-5.6.7.8", + "startIpAddress": "1.2.3.4" + } + ] + } + }, + "nodeType": { + "value": "Shard" + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "" + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "60395919-cfd3-47bf-8349-775ddebb255e", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin003' +param administratorLoginPassword = '' +param name = 'ddmcmax001' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param createMode = 'Default' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param highAvailabilityMode = false +param location = '' +param networkAcls = { + allowAllIPs: true + allowAzureIPs: true + customRules: [ + { + endIpAddress: '5.6.7.8' + firewallRuleName: 'allow-1.2.3.4-to-5.6.7.8' + startIpAddress: '1.2.3.4' + } + ] +} +param nodeType = 'Shard' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
    +

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

    + +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin001' + administratorLoginPassword: '' + name: 'ddmcwaf001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "administratorLogin": { + "value": "Admin001" + }, + "administratorLoginPassword": { + "value": "" + }, + "name": { + "value": "ddmcwaf001" + }, + "nodeCount": { + "value": 2 + }, + "sku": { + "value": "M30" + }, + "storage": { + "value": 256 + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/document-db/mongo-cluster:' + +// Required parameters +param administratorLogin = 'Admin001' +param administratorLoginPassword = '' +param name = 'ddmcwaf001' +param nodeCount = 2 +param sku = 'M30' +param storage = 256 +// Non-required parameters +param location = '' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`administratorLogin`](#parameter-administratorlogin) | string | Username for admin user. | +| [`administratorLoginPassword`](#parameter-administratorloginpassword) | securestring | Password for admin user. | +| [`name`](#parameter-name) | string | Name of the Azure Cosmos DB MongoDB vCore cluster. | +| [`nodeCount`](#parameter-nodecount) | int | Number of nodes in the node group. | +| [`sku`](#parameter-sku) | string | SKU defines the CPU and memory that is provisioned for each node. | +| [`storage`](#parameter-storage) | int | Disk storage size for the node group in GB. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`createMode`](#parameter-createmode) | string | Mode to create the azure cosmos db mongodb vCore cluster. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`highAvailabilityMode`](#parameter-highavailabilitymode) | bool | Whether high availability is enabled on the node group. | +| [`location`](#parameter-location) | string | Default to current resource group scope location. Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`networkAcls`](#parameter-networkacls) | object | IP addresses to allow access to the cluster from. | +| [`nodeType`](#parameter-nodetype) | string | Deployed Node type in the node group. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | +| [`tags`](#parameter-tags) | object | Tags of the Database Account resource. | + +### Parameter: `administratorLogin` + +Username for admin user. + +- Required: Yes +- Type: string + +### Parameter: `administratorLoginPassword` + +Password for admin user. + +- Required: Yes +- Type: securestring + +### Parameter: `name` + +Name of the Azure Cosmos DB MongoDB vCore cluster. + +- Required: Yes +- Type: string + +### Parameter: `nodeCount` + +Number of nodes in the node group. + +- Required: Yes +- Type: int + +### Parameter: `sku` + +SKU defines the CPU and memory that is provisioned for each node. + +- Required: Yes +- Type: string + +### Parameter: `storage` + +Disk storage size for the node group in GB. + +- Required: Yes +- Type: int + +### Parameter: `createMode` + +Mode to create the azure cosmos db mongodb vCore cluster. + +- Required: No +- Type: string +- Default: `'Default'` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `highAvailabilityMode` + +Whether high availability is enabled on the node group. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Default to current resource group scope 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: `networkAcls` + +IP addresses to allow access to the cluster from. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowAllIPs`](#parameter-networkaclsallowallips) | bool | Indicates whether to allow all IP addresses. | +| [`allowAzureIPs`](#parameter-networkaclsallowazureips) | bool | Indicates whether to allow all Azure internal IP addresses. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`customRules`](#parameter-networkaclscustomrules) | array | List of custom firewall rules. | + +### Parameter: `networkAcls.allowAllIPs` + +Indicates whether to allow all IP addresses. + +- Required: Yes +- Type: bool + +### Parameter: `networkAcls.allowAzureIPs` + +Indicates whether to allow all Azure internal IP addresses. + +- Required: Yes +- Type: bool + +### Parameter: `networkAcls.customRules` + +List of custom firewall rules. + +- Required: No +- Type: array + +### Parameter: `nodeType` + +Deployed Node type in the node group. + +- Required: No +- Type: string +- Default: `'Shard'` + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`isManualConnection`](#parameter-privateendpointsismanualconnection) | bool | If Manual Private Link Connection is required. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | +| [`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". | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | Fqdn that resolves to private endpoint ip address. | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private ip addresses of the private endpoint. | + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +Fqdn that resolves to private endpoint ip address. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private ip addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsipconfigurationsname) | string | The name of the resource that is unique within a resource group. | +| [`properties`](#parameter-privateendpointsipconfigurationsproperties) | object | Properties of private endpoint IP configurations. | + +### Parameter: `privateEndpoints.ipConfigurations.name` + +The name of the resource that is unique within a resource group. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties` + +Properties of private endpoint IP configurations. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupId`](#parameter-privateendpointsipconfigurationspropertiesgroupid) | string | The ID of a group obtained from the remote resource that this private endpoint should connect to. | +| [`memberName`](#parameter-privateendpointsipconfigurationspropertiesmembername) | string | The member name of a group obtained from the remote resource that this private endpoint should connect to. | +| [`privateIPAddress`](#parameter-privateendpointsipconfigurationspropertiesprivateipaddress) | string | A private ip address obtained from the private endpoint's subnet. | + +### Parameter: `privateEndpoints.ipConfigurations.properties.groupId` + +The ID of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.memberName` + +The member name of a group obtained from the remote resource that this private endpoint should connect to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.ipConfigurations.properties.privateIPAddress` + +A private ip address obtained from the private endpoint's subnet. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.isManualConnection` + +If Manual Private Link Connection is required. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualConnectionRequestMessage` + +A message passed to the owner of the remote resource with the manual connection request. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup` + +The private DNS zone group to configure for the private endpoint. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` + +The name of the private DNS zone group config. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string + +### 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. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | 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-privateendpointsroleassignmentscondition) | 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-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-privateendpointsroleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.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: `privateEndpoints.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: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.service` + +The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` + +**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. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`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.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- 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: `secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultResourceId`](#parameter-secretsexportconfigurationkeyvaultresourceid) | string | The resource ID of the key vault where to store the secrets of this module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`connectionStringSecretName`](#parameter-secretsexportconfigurationconnectionstringsecretname) | string | The name to use when creating the primary write connection string secret. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The resource ID of the key vault where to store the secrets of this module. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.connectionStringSecretName` + +The name to use when creating the primary write connection string secret. + +- Required: No +- Type: string + +### Parameter: `tags` + +Tags of the Database Account resource. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `connectionStringKey` | string | The connection string key of the mongo cluster. | +| `exportedSecrets` | | The references to the secrets exported to the provided Key Vault. | +| `firewallRules` | array | The name and resource ID of firewall rule. | +| `mongoClusterResourceId` | string | The resource ID of the Azure Cosmos DB MongoDB vCore cluster. | +| `name` | string | The name of the Azure Cosmos DB MongoDB vCore cluster. | +| `privateEndpoints` | array | The private endpoints of the database account. | +| `resourceGroupName` | string | The name of the resource group the firewall rule was created in. | +| `resourceId` | string | The resource ID of the resource group the firewall rule was created in. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.7.1` | Remote reference | + +## 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/document-db/mongo-cluster/firewall-rule/README.md b/avm/res/document-db/mongo-cluster/firewall-rule/README.md new file mode 100644 index 0000000000..c60b28b7db --- /dev/null +++ b/avm/res/document-db/mongo-cluster/firewall-rule/README.md @@ -0,0 +1,67 @@ +# Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules `[Microsoft.DocumentDB/mongoClusters/firewallRules]` + +This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.DocumentDB/mongoClusters/firewallRules` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters/firewallRules) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endIpAddress`](#parameter-endipaddress) | string | The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. | +| [`name`](#parameter-name) | string | The name of the firewall rule. | +| [`startIpAddress`](#parameter-startipaddress) | string | The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`mongoClusterName`](#parameter-mongoclustername) | string | The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment. | + +### Parameter: `endIpAddress` + +The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the firewall rule. + +- Required: Yes +- Type: string + +### Parameter: `startIpAddress` + +The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format. + +- Required: Yes +- Type: string + +### Parameter: `mongoClusterName` + +The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the firewall rule. | +| `resourceGroupName` | string | The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in. | +| `resourceId` | string | The resource ID of the firewall rule. | diff --git a/avm/res/document-db/mongo-cluster/firewall-rule/main.bicep b/avm/res/document-db/mongo-cluster/firewall-rule/main.bicep new file mode 100644 index 0000000000..38ea336d6b --- /dev/null +++ b/avm/res/document-db/mongo-cluster/firewall-rule/main.bicep @@ -0,0 +1,37 @@ +metadata name = 'Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules' +metadata description = 'This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster.' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment.') +param mongoClusterName string + +@description('Required. The name of the firewall rule.') +param name string + +@description('Required. The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format.') +param startIpAddress string + +@description('Required. The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format.') +param endIpAddress string + +resource mongoCluster 'Microsoft.DocumentDB/mongoClusters@2024-02-15-preview' existing = { + name: mongoClusterName +} + +resource firewallRule 'Microsoft.DocumentDB/mongoClusters/firewallRules@2024-02-15-preview' = { + name: name + parent: mongoCluster + properties: { + startIpAddress: startIpAddress + endIpAddress: endIpAddress + } +} + +@description('The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The name of the firewall rule.') +output name string = firewallRule.name + +@description('The resource ID of the firewall rule.') +output resourceId string = firewallRule.id diff --git a/avm/res/document-db/mongo-cluster/firewall-rule/main.json b/avm/res/document-db/mongo-cluster/firewall-rule/main.json new file mode 100644 index 0000000000..227ec11c2e --- /dev/null +++ b/avm/res/document-db/mongo-cluster/firewall-rule/main.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.27.1.19265", + "templateHash": "11076682219298980277" + }, + "name": "Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules", + "description": "This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "mongoClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the firewall rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/mongoClusters/firewallRules", + "apiVersion": "2024-02-15-preview", + "name": "[format('{0}/{1}', parameters('mongoClusterName'), parameters('name'))]", + "properties": { + "startIpAddress": "[parameters('startIpAddress')]", + "endIpAddress": "[parameters('endIpAddress')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the firewall rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the firewall rule." + }, + "value": "[resourceId('Microsoft.DocumentDB/mongoClusters/firewallRules', parameters('mongoClusterName'), parameters('name'))]" + } + } +} \ No newline at end of file diff --git a/avm/res/document-db/mongo-cluster/main.bicep b/avm/res/document-db/mongo-cluster/main.bicep new file mode 100644 index 0000000000..d4612a2a44 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/main.bicep @@ -0,0 +1,535 @@ +metadata name = 'Azure Cosmos DB MongoDB vCore cluster' +metadata description = '''This module deploys a Azure Cosmos DB MongoDB vCore cluster. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the Azure Cosmos DB MongoDB vCore cluster.') +param name string + +@description('Optional. Default to current resource group scope location. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the Database Account resource.') +param tags object? + +@description('Required. Username for admin user.') +param administratorLogin string + +@secure() +@description('Required. Password for admin user.') +@minLength(8) +@maxLength(128) +param administratorLoginPassword string + +@description('Optional. Mode to create the azure cosmos db mongodb vCore cluster.') +param createMode string = 'Default' + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Whether high availability is enabled on the node group.') +param highAvailabilityMode bool = false + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. IP addresses to allow access to the cluster from.') +param networkAcls networkAclsType? + +@description('Required. Number of nodes in the node group.') +param nodeCount int + +@description('Optional. Deployed Node type in the node group.') +param nodeType string = 'Shard' + +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +@description('Required. SKU defines the CPU and memory that is provisioned for each node.') +param sku string + +@description('Required. Disk storage size for the node group in GB.') +param storage int + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var firewallRules = union( + map(networkAcls.?customRules ?? [], customRule => { + name: customRule.?firewallRuleName ?? 'allow-${replace(customRule.startIpAddress, '.', '')}-to-${replace(customRule.endIpAddress, '.', '')}' + startIpAddress: customRule.startIpAddress + endIpAddress: customRule.endIpAddress + }), + networkAcls.?allowAllIPs ?? false + ? [ + { + name: 'allow-all-IPs' + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + ] + : [], + networkAcls.?allowAzureIPs ?? false + ? [ + { + name: 'allow-all-azure-internal-IPs' + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + ] + : [] +) + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.documentdb-mongocluster.${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 mongoCluster 'Microsoft.DocumentDB/mongoClusters@2024-02-15-preview' = { + name: name + tags: tags + location: location + properties: { + administratorLogin: administratorLogin + administratorLoginPassword: administratorLoginPassword + createMode: createMode + nodeGroupSpecs: [ + { + diskSizeGB: storage + enableHa: highAvailabilityMode + kind: nodeType + nodeCount: nodeCount + sku: sku + } + ] + } +} + +resource mongoCluster_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: mongoCluster + } +] + +resource mongoCluster_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(mongoCluster.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + 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: mongoCluster + } +] + +module mongoCluster_configFireWallRules 'firewall-rule/main.bicep' = [ + for (firewallRule, index) in firewallRules: { + name: '${uniqueString(deployment().name, location)}-firewallRule-${index}' + params: { + mongoClusterName: mongoCluster.name + name: firewallRule.name + startIpAddress: firewallRule.startIpAddress + endIpAddress: firewallRule.endIpAddress + } + } +] + +module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split((secretsExportConfiguration.?keyVaultResourceId ?? '//'), '/')[2], + split((secretsExportConfiguration.?keyVaultResourceId ?? '////'), '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId ?? '//', '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'connectionStringSecretName') + ? [ + { + name: secretsExportConfiguration!.connectionStringSecretName + value: mongoCluster.properties.connectionString + } + ] + : [] + ) + } +} + +module mongoCluster_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.7.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-databaseAccount-PrivateEndpoint-${index}' + scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(mongoCluster.id, '/'))}-${privateEndpoint.?service ?? 'mongoCluster'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(mongoCluster.id, '/'))}-${privateEndpoint.?service ?? 'mongoCluster'}-${index}' + properties: { + privateLinkServiceId: mongoCluster.id + groupIds: [ + privateEndpoint.?service ?? 'mongoCluster' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(mongoCluster.id, '/'))}-${privateEndpoint.?service ?? 'mongoCluster'}-${index}' + properties: { + privateLinkServiceId: mongoCluster.id + groupIds: [ + privateEndpoint.?service ?? 'mongoCluster' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +@description('The name of the Azure Cosmos DB MongoDB vCore cluster.') +output name string = mongoCluster.name + +@description('The resource ID of the Azure Cosmos DB MongoDB vCore cluster.') +output mongoClusterResourceId string = mongoCluster.id + +@description('The resource ID of the resource group the firewall rule was created in.') +output resourceId string = resourceGroup().id + +@description('The name of the resource group the firewall rule was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The connection string key of the mongo cluster.') +output connectionStringKey string = mongoCluster.properties.connectionString + +@description('The name and resource ID of firewall rule.') +output firewallRules firewallSetType[] = [ + for index in range(0, length(firewallRules ?? [])): { + name: mongoCluster_configFireWallRules[index].outputs.name + resourceId: mongoCluster_configFireWallRules[index].outputs.resourceId + } +] + +@description('The private endpoints of the database account.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: mongoCluster_privateEndpoints[i].outputs.name + resourceId: mongoCluster_privateEndpoints[i].outputs.resourceId + groupId: mongoCluster_privateEndpoints[i].outputs.groupId + customDnsConfig: mongoCluster_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: mongoCluster_privateEndpoints[i].outputs.networkInterfaceIds + } +] + +@description('The references to the secrets exported to the provided Key Vault.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +// =============== // +// Definitions // +// =============== // + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? + +type firewallSetType = { + @description('The name of the created firewall rule.') + name: string + + @description('The resource ID of the created firewall rule.') + resourceId: string +} + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type networkAclsType = { + @description('Optional. List of custom firewall rules.') + customRules: [ + { + @description('Optional. The name of the custom firewall rule.') + firewallRuleName: string? + + @description('Required. The starting IP address for the custom firewall rule.') + startIpAddress: string + + @description('Required. The ending IP address for the custom firewall rule.') + endIpAddress: string + } + ]? + + @description('Required. Indicates whether to allow all IP addresses.') + allowAllIPs: bool + + @description('Required. Indicates whether to allow all Azure internal IP addresses.') + allowAzureIPs: bool +} + +type privateEndpointType = { + @description('Optional. The name of the private endpoint.') + name: string? + + @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? + + @description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @description('Optional. The private DNS zone group to configure for the private endpoint.') + privateDnsZoneGroup: { + @description('Optional. The name of the Private DNS Zone Group.') + name: string? + + @description('Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneGroupConfigs: { + @description('Optional. The name of the private DNS zone group config.') + name: string? + + @description('Required. The resource id of the private DNS zone.') + privateDnsZoneResourceId: string + }[] + }? + + @description('Optional. If Manual Private Link Connection is required.') + isManualConnection: bool? + + @description('Optional. A message passed to the owner of the remote resource with the manual connection request.') + @maxLength(140) + manualConnectionRequestMessage: string? + + @description('Optional. Custom DNS configurations.') + customDnsConfigs: { + @description('Required. Fqdn that resolves to private endpoint ip address.') + fqdn: string? + + @description('Required. A list of private ip addresses of the private endpoint.') + ipAddresses: string[] + }[]? + + @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') + name: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private ip address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } + }[]? + + @description('Optional. Application security groups in which the private endpoint IP configuration is included.') + applicationSecurityGroupResourceIds: string[]? + + @description('Optional. The custom name of the network interface attached to the private endpoint.') + customNetworkInterfaceName: string? + + @description('Optional. Specify the type of lock.') + lock: lockType + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') + tags: object? + + @description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? + + @description('Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource.') + resourceGroupName: string? +}[]? + +type roleAssignmentType = { + @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @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? +}[]? + +type secretsExportConfigurationType = { + @description('Required. The resource ID of the key vault where to store the secrets of this module.') + keyVaultResourceId: string + + @description('Optional. The name to use when creating the primary write connection string secret.') + connectionStringSecretName: string? +} + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/document-db/mongo-cluster/main.json b/avm/res/document-db/mongo-cluster/main.json new file mode 100644 index 0000000000..9d963be7d0 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/main.json @@ -0,0 +1,1898 @@ +{ + "$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.27.1.19265", + "templateHash": "289094531739005234" + }, + "name": "Azure Cosmos DB MongoDB vCore cluster", + "description": "This module deploys a Azure Cosmos DB MongoDB vCore cluster.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "firewallSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the created firewall rule." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the created firewall rule." + } + } + } + }, + "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 + }, + "networkAclsType": { + "type": "object", + "properties": { + "customRules": { + "type": "array", + "prefixItems": [ + { + "type": "object", + "properties": { + "firewallRuleName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the custom firewall rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The starting IP address for the custom firewall rule." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The ending IP address for the custom firewall rule." + } + } + } + } + ], + "items": false, + "nullable": true, + "metadata": { + "description": "Optional. List of custom firewall rules." + } + }, + "allowAllIPs": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether to allow all IP addresses." + } + }, + "allowAzureIPs": { + "type": "bool", + "metadata": { + "description": "Required. Indicates whether to allow all Azure internal IP addresses." + } + } + } + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "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, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the key vault where to store the secrets of this module." + } + }, + "connectionStringSecretName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name to use when creating the primary write connection string secret." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Azure Cosmos DB MongoDB vCore cluster." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Default to current resource group scope location. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the Database Account resource." + } + }, + "administratorLogin": { + "type": "string", + "metadata": { + "description": "Required. Username for admin user." + } + }, + "administratorLoginPassword": { + "type": "securestring", + "minLength": 8, + "maxLength": 128, + "metadata": { + "description": "Required. Password for admin user." + } + }, + "createMode": { + "type": "string", + "defaultValue": "Default", + "metadata": { + "description": "Optional. Mode to create the azure cosmos db mongodb vCore cluster." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "highAvailabilityMode": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether high availability is enabled on the node group." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "networkAcls": { + "$ref": "#/definitions/networkAclsType", + "nullable": true, + "metadata": { + "description": "Optional. IP addresses to allow access to the cluster from." + } + }, + "nodeCount": { + "type": "int", + "metadata": { + "description": "Required. Number of nodes in the node group." + } + }, + "nodeType": { + "type": "string", + "defaultValue": "Shard", + "metadata": { + "description": "Optional. Deployed Node type in the node group." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "sku": { + "type": "string", + "metadata": { + "description": "Required. SKU defines the CPU and memory that is provisioned for each node." + } + }, + "storage": { + "type": "int", + "metadata": { + "description": "Required. Disk storage size for the node group in GB." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + }, + "firewallRules": "[union(map(coalesce(tryGet(parameters('networkAcls'), 'customRules'), createArray()), lambda('customRule', createObject('name', coalesce(tryGet(lambdaVariables('customRule'), 'firewallRuleName'), format('allow-{0}-to-{1}', replace(lambdaVariables('customRule').startIpAddress, '.', ''), replace(lambdaVariables('customRule').endIpAddress, '.', ''))), 'startIpAddress', lambdaVariables('customRule').startIpAddress, 'endIpAddress', lambdaVariables('customRule').endIpAddress))), if(coalesce(tryGet(parameters('networkAcls'), 'allowAllIPs'), false()), createArray(createObject('name', 'allow-all-IPs', 'startIpAddress', '0.0.0.0', 'endIpAddress', '255.255.255.255')), createArray()), if(coalesce(tryGet(parameters('networkAcls'), 'allowAzureIPs'), false()), createArray(createObject('name', 'allow-all-azure-internal-IPs', 'startIpAddress', '0.0.0.0', 'endIpAddress', '0.0.0.0')), createArray()))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.documentdb-mongocluster.{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" + } + } + } + } + }, + "mongoCluster": { + "type": "Microsoft.DocumentDB/mongoClusters", + "apiVersion": "2024-02-15-preview", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "administratorLogin": "[parameters('administratorLogin')]", + "administratorLoginPassword": "[parameters('administratorLoginPassword')]", + "createMode": "[parameters('createMode')]", + "nodeGroupSpecs": [ + { + "diskSizeGB": "[parameters('storage')]", + "enableHa": "[parameters('highAvailabilityMode')]", + "kind": "[parameters('nodeType')]", + "nodeCount": "[parameters('nodeCount')]", + "sku": "[parameters('sku')]" + } + ] + } + }, + "mongoCluster_diagnosticSettings": { + "copy": { + "name": "mongoCluster_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DocumentDB/mongoClusters/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "mongoCluster" + ] + }, + "mongoCluster_roleAssignments": { + "copy": { + "name": "mongoCluster_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DocumentDB/mongoClusters/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "mongoCluster" + ] + }, + "mongoCluster_configFireWallRules": { + "copy": { + "name": "mongoCluster_configFireWallRules", + "count": "[length(variables('firewallRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-firewallRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "mongoClusterName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[variables('firewallRules')[copyIndex()].name]" + }, + "startIpAddress": { + "value": "[variables('firewallRules')[copyIndex()].startIpAddress]" + }, + "endIpAddress": { + "value": "[variables('firewallRules')[copyIndex()].endIpAddress]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.27.1.19265", + "templateHash": "11076682219298980277" + }, + "name": "Azure Cosmos DB MongoDB vCore Cluster Config FireWall Rules", + "description": "This module config firewall rules for the Azure Cosmos DB MongoDB vCore cluster.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "mongoClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Cosmos DB MongoDB vCore cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the firewall rule." + } + }, + "startIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The start IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + }, + "endIpAddress": { + "type": "string", + "metadata": { + "description": "Required. The end IP address of the Azure Cosmos DB MongoDB vCore cluster firewall rule. Must be IPv4 format." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/mongoClusters/firewallRules", + "apiVersion": "2024-02-15-preview", + "name": "[format('{0}/{1}', parameters('mongoClusterName'), parameters('name'))]", + "properties": { + "startIpAddress": "[parameters('startIpAddress')]", + "endIpAddress": "[parameters('endIpAddress')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Azure Cosmos DB MongoDB vCore cluster was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the firewall rule." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the firewall rule." + }, + "value": "[resourceId('Microsoft.DocumentDB/mongoClusters/firewallRules', parameters('mongoClusterName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "mongoCluster" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '////'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'connectionStringSecretName'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionStringSecretName, 'value', reference('mongoCluster').connectionString)), createArray()))]" + } + }, + "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.27.1.19265", + "templateHash": "4835482779180953345" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the secrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "mongoCluster" + ] + }, + "mongoCluster_privateEndpoints": { + "copy": { + "name": "mongoCluster_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-databaseAccount-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'mongoCluster')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "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.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "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 to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "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.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "mongoCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Azure Cosmos DB MongoDB vCore cluster." + }, + "value": "[parameters('name')]" + }, + "mongoClusterResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure Cosmos DB MongoDB vCore cluster." + }, + "value": "[resourceId('Microsoft.DocumentDB/mongoClusters', parameters('name'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the resource group the firewall rule was created in." + }, + "value": "[resourceGroup().id]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the firewall rule was created in." + }, + "value": "[resourceGroup().name]" + }, + "connectionStringKey": { + "type": "string", + "metadata": { + "description": "The connection string key of the mongo cluster." + }, + "value": "[reference('mongoCluster').connectionString]" + }, + "firewallRules": { + "type": "array", + "items": { + "$ref": "#/definitions/firewallSetType" + }, + "metadata": { + "description": "The name and resource ID of firewall rule." + }, + "copy": { + "count": "[length(range(0, length(coalesce(variables('firewallRules'), createArray()))))]", + "input": { + "name": "[reference(format('mongoCluster_configFireWallRules[{0}]', range(0, length(coalesce(variables('firewallRules'), createArray())))[copyIndex()])).outputs.name.value]", + "resourceId": "[reference(format('mongoCluster_configFireWallRules[{0}]', range(0, length(coalesce(variables('firewallRules'), createArray())))[copyIndex()])).outputs.resourceId.value]" + } + } + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the database account." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('mongoCluster_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + } + } +} \ No newline at end of file diff --git a/avm/res/document-db/mongo-cluster/modules/keyVaultExport.bicep b/avm/res/document-db/mongo-cluster/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..1bd329ba99 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/modules/keyVaultExport.bicep @@ -0,0 +1,50 @@ +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..536ed8e984 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-documentdb-mongoclusters-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ddmcdefmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + administratorLogin: 'Admin001' + administratorLoginPassword: password + nodeCount: 2 + sku: 'M30' + storage: 256 + } + } +] diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/dependencies.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 0000000000..d3eadbfb8f --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + enableRbacAuthorization: true + tenantId: subscription().tenantId + } +} + +@description('The resource Id of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 0000000000..82a5ecbb26 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,72 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving its secrets in a key vault.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-documentdb.databaseaccounts-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'dddaskvs' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============== // +// General resources +// ============== // +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + location: resourceLocation + name: '${namePrefix}-kv-ref' + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + connectionStringSecretName: 'connectionString' + } + administratorLogin: 'Admin002' + administratorLoginPassword: password + nodeCount: 2 + sku: 'M30' + storage: 256 + } +} + +// Output usage examples +output specificSecret string = testDeployment.outputs.exportedSecrets.connectionString.secretResourceId +output allEportedSecrets object = testDeployment.outputs.exportedSecrets +output allExportedSecretResourceIds array = map( + items(testDeployment.outputs.exportedSecrets), + item => item.value.secretResourceId +) diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/max/dependencies.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..16d9a64d1b --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/max/dependencies.bicep @@ -0,0 +1,102 @@ +@description('Optional. The location to deploy resources 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 Deployment Script to create to get the paired region name.') +param pairedRegionScriptName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink${environment().suffixes.acrLoginServer}' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${location}-${managedIdentity.id}-Reader-RoleAssignment') + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) // Reader + principalType: 'ServicePrincipal' + } +} + +resource getPairedRegionScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: pairedRegionScriptName + location: location + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.0' + retentionInterval: 'P1D' + arguments: '-Location \\"${location}\\"' + scriptContent: loadTextContent('../../../../../../utilities/e2e-template-assets/scripts/Get-PairedRegion.ps1') + } + dependsOn: [ + roleAssignment + ] +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The name of the paired region.') +output pairedRegionName string = getPairedRegionScript.properties.outputs.pairedRegionName diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..e8127df0e3 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/max/main.test.bicep @@ -0,0 +1,163 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with the maximum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-documentdb-mongoclusters-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ddmcmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-ds-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + pairedRegionScriptName: 'dep-${namePrefix}-ds-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + administratorLogin: 'Admin003' + administratorLoginPassword: password + createMode: 'Default' + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + highAvailabilityMode: false + networkAcls: { + customRules: [ + { + firewallRuleName: 'allow-1.2.3.4-to-5.6.7.8' + endIpAddress: '5.6.7.8' + startIpAddress: '1.2.3.4' + } + ] + allowAzureIPs: true + allowAllIPs: true + } + nodeCount: 2 + nodeType: 'Shard' + privateEndpoints: [ + { + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + subnetResourceId: nestedDependencies.outputs.subnetResourceId + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + } + ] + roleAssignments: [ + { + name: '60395919-cfd3-47bf-8349-775ddebb255e' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + 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' + } + ] + sku: 'M30' + storage: 256 + } + dependsOn: [ + nestedDependencies + diagnosticDependencies + ] + } +] diff --git a/avm/res/document-db/mongo-cluster/tests/e2e/waf-aligned/main.test.bicep b/avm/res/document-db/mongo-cluster/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..4d098959c8 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,57 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-documentdb-mongoclusters-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ddmcwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + administratorLogin: 'Admin001' + administratorLoginPassword: password + nodeCount: 2 + sku: 'M30' + storage: 256 + } + } +] diff --git a/avm/res/document-db/mongo-cluster/version.json b/avm/res/document-db/mongo-cluster/version.json new file mode 100644 index 0000000000..eb30921b0c --- /dev/null +++ b/avm/res/document-db/mongo-cluster/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md index 7514b32c3d..7e0ec765a4 100644 --- a/avm/res/event-grid/domain/README.md +++ b/avm/res/event-grid/domain/README.md @@ -61,7 +61,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,22 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/domain:' + +// Required parameters +param name = 'egdmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -187,7 +203,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -301,6 +317,100 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/domain:' + +// Required parameters +param name = 'egdmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundIpRules = [ + { + action: 'Allow' + ipMask: '40.74.28.0/23' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '1d2dba39-c8fe-45f9-a3af-6dc15caa95a5' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + 'topic-egdmax001' +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -372,7 +482,7 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -451,6 +561,67 @@ module domain 'br/public:avm/res/event-grid/domain:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/domain:' + +// Required parameters +param name = 'egdwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundIpRules = [] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'domain' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + 'topic-egdwaf001' +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -1033,6 +1204,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1160,6 +1342,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/README.md b/avm/res/event-grid/namespace/README.md index 290a4d6631..68fe8bf4f3 100644 --- a/avm/res/event-grid/namespace/README.md +++ b/avm/res/event-grid/namespace/README.md @@ -69,7 +69,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -91,6 +91,22 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -299,7 +315,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -517,6 +533,204 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'bde32b53-e30c-41d0-a338-c637853fe524' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + { + eventRetentionInDays: 7 + eventSubscriptions: [ + { + deliveryConfiguration: { + deliveryMode: 'Queue' + queue: { + eventTimeToLive: 'P7D' + maxDeliveryCount: 10 + receiveLockDurationInSeconds: 60 + } + } + name: 'subscription1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + deliveryConfiguration: { + deliveryMode: 'Push' + push: { + deliveryWithResourceIdentity: { + destination: { + endpointType: 'EventHub' + properties: { + deliveryAttributeMappings: [ + { + name: 'StaticHeader1' + properties: { + isSecret: false + value: 'staticVaule' + } + type: 'Static' + } + { + name: 'DynamicHeader1' + properties: { + sourceField: 'id' + } + type: 'Dynamic' + } + { + name: 'StaticSecretHeader1' + properties: { + isSecret: true + value: 'Hidden' + } + type: 'Static' + } + ] + resourceId: '' + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentity: '' + } + } + eventTimeToLive: 'P7D' + maxDeliveryCount: 10 + } + } + name: 'subscription2' + } + ] + name: 'topic1' + } + { + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + name: 'topic2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +``` + +
    +

    + ### Example 3: _MQTT Broker with routing to a namespace topic_ This instance deploys the module as a MQTT Broker with routing to a topic within the same Eventgrid namespace. @@ -674,7 +888,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -853,6 +1067,153 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmqttct001' +// Non-required parameters +param alternativeAuthenticationNameSources = [ + 'ClientCertificateEmail' + 'ClientCertificateUri' +] +param clientGroups = [ + { + description: 'this is group1' + name: 'group1' + query: 'attributes.keyName IN [\'a\', \'b\', \'c\']' + } +] +param clients = [ + { + attributes: { + deviceTypes: [ + 'Fan' + 'Light' + ] + floor: 12 + room: '345' + } + authenticationName: 'client2auth' + clientCertificateAuthenticationAllowedThumbprints: [ + '1111111111111111111111111111111111111111' + '2222222222222222222222222222222222222222' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + description: 'this is client2' + name: 'client1' + state: 'Enabled' + } + { + clientCertificateAuthenticationAllowedThumbprints: [ + '3333333333333333333333333333333333333333' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + name: 'client2' + } + { + name: 'client3' + } + { + clientCertificateAuthenticationValidationSchema: 'IpMatchesAuthenticationName' + name: 'client4' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param maximumClientSessionsPerAuthenticationName = 5 +param maximumSessionExpiryInHours = 2 +param permissionBindings = [ + { + clientGroupName: 'group1' + description: 'this is binding1' + name: 'bindiing1' + permission: 'Publisher' + topicSpaceName: 'topicSpace1' + } + { + clientGroupName: 'group1' + name: 'bindiing2' + permission: 'Subscriber' + topicSpaceName: 'topicSpace2' + } +] +param routeTopicResourceId = '' +param routingEnrichments = { + dynamic: [ + { + key: 'dynamic1' + value: '' + } + ] + static: [ + { + key: 'static1' + value: 'value1' + valueType: 'String' + } + { + key: 'static2' + value: 'value2' + valueType: 'String' + } + ] +} +param routingIdentityInfo = { + type: 'UserAssigned' + userAssignedIdentity: '' +} +param topics = [ + { + name: 'topic1' + } +] +param topicSpaces = [ + { + name: 'topicSpace1' + topicTemplates: [ + 'devices/foo/bar' + 'devices/topic1/+' + ] + } + { + name: 'topicSpace2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + topicTemplates: [ + 'devices/topic1/+' + ] + } +] +param topicSpacesState = 'Enabled' +``` + +
    +

    + ### Example 4: _MQTT Broker with routing to a namespace topic_ This instance deploys the module as a MQTT Broker with routing to a topic within the same Eventgrid namespace. @@ -1010,7 +1371,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1189,6 +1550,153 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnmqttnt001' +// Non-required parameters +param alternativeAuthenticationNameSources = [ + 'ClientCertificateEmail' + 'ClientCertificateUri' +] +param clientGroups = [ + { + description: 'this is group1' + name: 'group1' + query: 'attributes.keyName IN [\'a\', \'b\', \'c\']' + } +] +param clients = [ + { + attributes: { + deviceTypes: [ + 'Fan' + 'Light' + ] + floor: 12 + room: '345' + } + authenticationName: 'client2auth' + clientCertificateAuthenticationAllowedThumbprints: [ + '1111111111111111111111111111111111111111' + '2222222222222222222222222222222222222222' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + description: 'this is client2' + name: 'client1' + state: 'Enabled' + } + { + clientCertificateAuthenticationAllowedThumbprints: [ + '3333333333333333333333333333333333333333' + ] + clientCertificateAuthenticationValidationSchema: 'ThumbprintMatch' + name: 'client2' + } + { + name: 'client3' + } + { + clientCertificateAuthenticationValidationSchema: 'IpMatchesAuthenticationName' + name: 'client4' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param maximumClientSessionsPerAuthenticationName = 5 +param maximumSessionExpiryInHours = 2 +param permissionBindings = [ + { + clientGroupName: 'group1' + description: 'this is binding1' + name: 'bindiing1' + permission: 'Publisher' + topicSpaceName: 'topicSpace1' + } + { + clientGroupName: 'group1' + name: 'bindiing2' + permission: 'Subscriber' + topicSpaceName: 'topicSpace2' + } +] +param routeTopicResourceId = '' +param routingEnrichments = { + dynamic: [ + { + key: 'dynamic1' + value: '' + } + ] + static: [ + { + key: 'static1' + value: 'value1' + valueType: 'String' + } + { + key: 'static2' + value: 'value2' + valueType: 'String' + } + ] +} +param routingIdentityInfo = { + type: 'UserAssigned' + userAssignedIdentity: '' +} +param topics = [ + { + name: 'topic1' + } +] +param topicSpaces = [ + { + name: 'topicSpace1' + topicTemplates: [ + 'devices/foo/bar' + 'devices/topic1/+' + ] + } + { + name: 'topicSpace2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + topicTemplates: [ + 'devices/topic1/+' + ] + } +] +param topicSpacesState = 'Enabled' +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1272,7 +1780,7 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1359,6 +1867,79 @@ module namespace 'br/public:avm/res/event-grid/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/namespace:' + +// Required parameters +param name = 'egnwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2006,6 +2587,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2132,6 +2724,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/topic-space/README.md b/avm/res/event-grid/namespace/topic-space/README.md index a931f6ad62..442efe3335 100644 --- a/avm/res/event-grid/namespace/topic-space/README.md +++ b/avm/res/event-grid/namespace/topic-space/README.md @@ -71,6 +71,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/topic/README.md b/avm/res/event-grid/namespace/topic/README.md index 8b0920ea45..9d831de41c 100644 --- a/avm/res/event-grid/namespace/topic/README.md +++ b/avm/res/event-grid/namespace/topic/README.md @@ -129,6 +129,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/namespace/topic/event-subscription/README.md b/avm/res/event-grid/namespace/topic/event-subscription/README.md index 8b2fcd5527..3efe652422 100644 --- a/avm/res/event-grid/namespace/topic/event-subscription/README.md +++ b/avm/res/event-grid/namespace/topic/event-subscription/README.md @@ -88,6 +88,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Resource Notifications System Topics Subscriber'` + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Contributor'` + - `'EventGrid Data Receiver'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'EventGrid TopicSpaces Publisher'` + - `'EventGrid TopicSpaces Subscriber'` + - `'Owner'` + - `'Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/system-topic/README.md b/avm/res/event-grid/system-topic/README.md index eb74e20320..51fd97f169 100644 --- a/avm/res/event-grid/system-topic/README.md +++ b/avm/res/event-grid/system-topic/README.md @@ -60,7 +60,7 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,24 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/system-topic:' + +// Required parameters +param name = 'egstmin001' +param source = '' +param topicType = 'Microsoft.Storage.StorageAccounts' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -184,7 +202,7 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -292,6 +310,92 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/system-topic:' + +// Required parameters +param name = 'egstmax001' +param source = '' +param topicType = 'Microsoft.Storage.StorageAccounts' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egstmax001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + name: 'c9beca28-efcf-4d1d-99aa-8f334484a2c2' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -366,7 +470,7 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -448,6 +552,70 @@ module systemTopic 'br/public:avm/res/event-grid/system-topic:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/system-topic:' + +// Required parameters +param name = 'egstwaf001' +param source = '' +param topicType = 'Microsoft.Storage.StorageAccounts' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egstwaf001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -732,6 +900,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md index 56864ec710..fcb7a52ee0 100644 --- a/avm/res/event-grid/topic/README.md +++ b/avm/res/event-grid/topic/README.md @@ -61,7 +61,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,22 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/topic:' + +// Required parameters +param name = 'egtmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -219,7 +235,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -365,6 +381,132 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/topic:' + +// Required parameters +param name = 'egtmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egtmax001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param inboundIpRules = [ + { + action: 'Allow' + ipMask: '40.74.28.0/23' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'f80d2f24-53f6-41b3-811f-668b2273dcf8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -456,7 +598,7 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -555,6 +697,87 @@ module topic 'br/public:avm/res/event-grid/topic:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-grid/topic:' + +// Required parameters +param name = 'egtwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventSubscriptions = [ + { + destination: { + endpointType: 'StorageQueue' + properties: { + queueMessageTimeToLiveInSeconds: 86400 + queueName: '' + resourceId: '' + } + } + eventDeliverySchema: 'CloudEventSchemaV1_0' + expirationTimeUtc: '2099-01-01T11:00:21.715Z' + filter: { + enableAdvancedFilteringOnArrays: true + isSubjectCaseSensitive: false + } + name: 'egtwaf001' + retryPolicy: { + eventTimeToLive: '120' + maxDeliveryAttempts: 10 + } + } +] +param inboundIpRules = [] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'topic' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1127,6 +1350,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1254,6 +1488,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'EventGrid Contributor'` + - `'EventGrid Data Sender'` + - `'EventGrid EventSubscription Contributor'` + - `'EventGrid EventSubscription Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-hub/namespace/README.md b/avm/res/event-hub/namespace/README.md index aae733f8da..03faa22348 100644 --- a/avm/res/event-hub/namespace/README.md +++ b/avm/res/event-hub/namespace/README.md @@ -67,7 +67,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,22 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using encryption with Customer-Managed-Key_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -128,7 +144,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -171,6 +187,35 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnenc001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param requireInfrastructureEncryption = true +param skuName = 'Premium' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -370,7 +415,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -601,6 +646,195 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnmax001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param eventhubs = [ + { + name: 'az-evh-x-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } + ] + captureDescriptionDestinationArchiveNameFormat: '{Namespace}/{EventHub}/{PartitionId}/{Year}/{Month}/{Day}/{Hour}/{Minute}/{Second}' + captureDescriptionDestinationBlobContainer: 'eventhub' + captureDescriptionDestinationName: 'EventHubArchive.AzureBlockBlob' + captureDescriptionDestinationStorageAccountResourceId: '' + captureDescriptionEnabled: true + captureDescriptionEncoding: 'Avro' + captureDescriptionIntervalInSeconds: 300 + captureDescriptionSizeLimitInBytes: 314572800 + captureDescriptionSkipEmptyArchives: true + consumergroups: [ + { + name: 'custom' + userMetadata: 'customMetadata' + } + ] + messageRetentionInDays: 1 + name: 'az-evh-x-002' + partitionCount: 2 + retentionDescriptionCleanupPolicy: 'Delete' + retentionDescriptionRetentionTimeInHours: 3 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + status: 'Active' + } + { + name: 'az-evh-x-003' + retentionDescriptionCleanupPolicy: 'Compact' + retentionDescriptionTombstoneRetentionTimeInHours: 24 + } +] +param isAutoInflateEnabled = true +param kafkaEnabled = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param maximumThroughputUnits = 4 +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.10.10.10' + } + ] + publicNetworkAccess: 'Disabled' + trustedServiceAccessEnabled: false + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: 'bd0f41e3-8e3e-4cd3-b028-edd61608bd9f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 2 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneRedundant = true +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -754,7 +988,7 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -931,6 +1165,149 @@ module namespace 'br/public:avm/res/event-hub/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/event-hub/namespace:' + +// Required parameters +param name = 'ehnwaf001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param eventhubs = [ + { + name: 'az-evh-x-001' + } + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'SendListenAccess' + rights: [ + 'Listen' + 'Send' + ] + } + ] + captureDescriptionDestinationArchiveNameFormat: '{Namespace}/{EventHub}/{PartitionId}/{Year}/{Month}/{Day}/{Hour}/{Minute}/{Second}' + captureDescriptionDestinationBlobContainer: 'eventhub' + captureDescriptionDestinationName: 'EventHubArchive.AzureBlockBlob' + captureDescriptionDestinationStorageAccountResourceId: '' + captureDescriptionEnabled: true + captureDescriptionEncoding: 'Avro' + captureDescriptionIntervalInSeconds: 300 + captureDescriptionSizeLimitInBytes: 314572800 + captureDescriptionSkipEmptyArchives: true + consumergroups: [ + { + name: 'custom' + userMetadata: 'customMetadata' + } + ] + messageRetentionInDays: 1 + name: 'az-evh-x-002' + partitionCount: 2 + retentionDescriptionCleanupPolicy: 'Delete' + retentionDescriptionRetentionTimeInHours: 3 + status: 'Active' + } + { + name: 'az-evh-x-003' + retentionDescriptionCleanupPolicy: 'Compact' + retentionDescriptionTombstoneRetentionTimeInHours: 24 + } +] +param isAutoInflateEnabled = true +param kafkaEnabled = true +param location = '' +param maximumThroughputUnits = 4 +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.10.10.10' + } + ] + trustedServiceAccessEnabled: false + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Disabled' +param skuCapacity = 2 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1631,6 +2008,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1767,6 +2155,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Event Hubs Data Owner'` + - `'Azure Event Hubs Data Receiver'` + - `'Azure Event Hubs Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/event-hub/namespace/eventhub/README.md b/avm/res/event-hub/namespace/eventhub/README.md index 8964602f1b..b10aa5e66f 100644 --- a/avm/res/event-hub/namespace/eventhub/README.md +++ b/avm/res/event-hub/namespace/eventhub/README.md @@ -273,6 +273,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Event Hubs Data Owner'` + - `'Azure Event Hubs Data Receiver'` + - `'Azure Event Hubs Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/fabric/capacity/README.md b/avm/res/fabric/capacity/README.md new file mode 100644 index 0000000000..8cec8824cb --- /dev/null +++ b/avm/res/fabric/capacity/README.md @@ -0,0 +1,290 @@ +# Fabric Capacities `[Microsoft.Fabric/capacities]` + +This module deploys Fabric capacities, which provide the compute resources for all the experiences in Fabric. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Fabric/capacities` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates) | + +## 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/fabric/capacity:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [WAF-aligned](#example-2-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module capacity 'br/public:avm/res/fabric/capacity:' = { + name: 'capacityDeployment' + params: { + // Required parameters + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + name: 'fcmin001' + // Non-required parameters + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminMembers": { + "value": [ + "mattschmitt@microsoft.com" + ] + }, + "name": { + "value": "fcmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/fabric/capacity:' + +// Required parameters +param adminMembers = [ + 'mattschmitt@microsoft.com' +] +param name = 'fcmin001' +// Non-required parameters +param location = '' +``` + +
    +

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

    + +via Bicep module + +```bicep +module capacity 'br/public:avm/res/fabric/capacity:' = { + name: 'capacityDeployment' + params: { + // Required parameters + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + name: 'fcwaf001' + // Non-required parameters + location: '' + skuName: 'F64' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "adminMembers": { + "value": [ + "mattschmitt@microsoft.com" + ] + }, + "name": { + "value": "fcwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "skuName": { + "value": "F64" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/fabric/capacity:' + +// Required parameters +param adminMembers = [ + 'mattschmitt@microsoft.com' +] +param name = 'fcwaf001' +// Non-required parameters +param location = '' +param skuName = 'F64' +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`adminMembers`](#parameter-adminmembers) | array | List of admin members. Format: ["something@domain.com"]. | +| [`name`](#parameter-name) | string | Name of the resource to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`skuName`](#parameter-skuname) | string | SKU tier of the Fabric resource. | +| [`skuTier`](#parameter-skutier) | string | SKU name of the Fabric resource. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `adminMembers` + +List of admin members. Format: ["something@domain.com"]. + +- Required: Yes +- Type: array + +### Parameter: `name` + +Name of the resource to create. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `skuName` + +SKU tier of the Fabric resource. + +- Required: No +- Type: string +- Default: `'F2'` +- Allowed: + ```Bicep + [ + 'F1024' + 'F128' + 'F16' + 'F2' + 'F2048' + 'F256' + 'F32' + 'F4' + 'F512' + 'F64' + 'F8' + ] + ``` + +### Parameter: `skuTier` + +SKU name of the Fabric resource. + +- Required: No +- Type: string +- Default: `'Fabric'` +- Allowed: + ```Bicep + [ + 'Fabric' + ] + ``` + +### 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 Fabric resource. | +| `resourceGroupName` | string | The name of the resource group the module was deployed to. | +| `resourceId` | string | The resource ID of the deployed Fabric resource. | + +## 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/fabric/capacity/main.bicep b/avm/res/fabric/capacity/main.bicep new file mode 100644 index 0000000000..3e855ad580 --- /dev/null +++ b/avm/res/fabric/capacity/main.bicep @@ -0,0 +1,92 @@ +metadata name = 'Fabric Capacities' +metadata description = 'This module deploys Fabric capacities, which provide the compute resources for all the experiences in Fabric.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the resource to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@allowed([ + 'F2' + 'F4' + 'F8' + 'F16' + 'F32' + 'F64' + 'F128' + 'F256' + 'F512' + 'F1024' + 'F2048' +]) +@description('Optional. SKU tier of the Fabric resource.') +param skuName string = 'F2' + +@allowed(['Fabric']) +@description('Optional. SKU name of the Fabric resource.') +param skuTier string = 'Fabric' + +@description('Required. List of admin members. Format: ["something@domain.com"].') +param adminMembers array + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.fabric-capacity.${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 fabricCapacity 'Microsoft.Fabric/capacities@2023-11-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + properties: { + administration: { + members: adminMembers + } + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the resource group the module was deployed to.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the deployed Fabric resource.') +output resourceId string = fabricCapacity.id + +@description('The name of the deployed Fabric resource.') +output name string = fabricCapacity.name + +@description('The location the resource was deployed into.') +output location string = fabricCapacity.location diff --git a/avm/res/fabric/capacity/main.json b/avm/res/fabric/capacity/main.json new file mode 100644 index 0000000000..c6d0daee58 --- /dev/null +++ b/avm/res/fabric/capacity/main.json @@ -0,0 +1,148 @@ +{ + "$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.30.3.12046", + "templateHash": "11718641793898572278" + }, + "name": "Fabric Capacities", + "description": "This module deploys Fabric capacities, which provide the compute resources for all the experiences in Fabric.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "skuName": { + "type": "string", + "defaultValue": "F2", + "allowedValues": [ + "F2", + "F4", + "F8", + "F16", + "F32", + "F64", + "F128", + "F256", + "F512", + "F1024", + "F2048" + ], + "metadata": { + "description": "Optional. SKU tier of the Fabric resource." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Fabric", + "allowedValues": [ + "Fabric" + ], + "metadata": { + "description": "Optional. SKU name of the Fabric resource." + } + }, + "adminMembers": { + "type": "array", + "metadata": { + "description": "Required. List of admin members. Format: [\"something@domain.com\"]." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.fabric-capacity.{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" + } + } + } + } + }, + "fabricCapacity": { + "type": "Microsoft.Fabric/capacities", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "properties": { + "administration": { + "members": "[parameters('adminMembers')]" + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the module was deployed to." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed Fabric resource." + }, + "value": "[resourceId('Microsoft.Fabric/capacities', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed Fabric resource." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('fabricCapacity', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep b/avm/res/fabric/capacity/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..a0057419f4 --- /dev/null +++ b/avm/res/fabric/capacity/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 = 'dep-${namePrefix}-fabric-capacities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'fcmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + } + } +] diff --git a/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep b/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..903ccd6b35 --- /dev/null +++ b/avm/res/fabric/capacity/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,52 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-fabric-capacities-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'fcwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + skuName: 'F64' + adminMembers: [ + 'mattschmitt@microsoft.com' + ] + } + } +] diff --git a/avm/res/fabric/capacity/version.json b/avm/res/fabric/capacity/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/fabric/capacity/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/health-bot/health-bot/README.md b/avm/res/health-bot/health-bot/README.md index 032ebd2d90..073a60ffba 100644 --- a/avm/res/health-bot/health-bot/README.md +++ b/avm/res/health-bot/health-bot/README.md @@ -62,7 +62,7 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,23 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/health-bot/health-bot:' + +// Required parameters +param name = 'hbhbmin002' +param sku = 'F0' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -147,7 +164,7 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -213,6 +230,56 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/health-bot/health-bot:' + +// Required parameters +param name = 'hbhbmax002' +param sku = 'F0' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '9d89b5ea-0d1f-41d8-9297-52529827d712' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -249,7 +316,7 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -287,6 +354,32 @@ module healthBot 'br/public:avm/res/health-bot/health-bot:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/health-bot/health-bot:' + +// Required parameters +param name = 'hbhbwaf002' +param sku = 'F0' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -407,6 +500,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/healthcare-apis/workspace/README.md b/avm/res/healthcare-apis/workspace/README.md index 3347555bd9..66c2b983fa 100644 --- a/avm/res/healthcare-apis/workspace/README.md +++ b/avm/res/healthcare-apis/workspace/README.md @@ -67,7 +67,7 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -89,6 +89,22 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/healthcare-apis/workspace:' + +// Required parameters +param name = 'hawmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -244,7 +260,7 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -407,6 +423,151 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/healthcare-apis/workspace:' + +// Required parameters +param name = 'hawmax001' +// Non-required parameters +param dicomservices = [ + { + corsAllowCredentials: false + corsHeaders: [ + '*' + ] + corsMaxAge: 600 + corsMethods: [ + 'GET' + ] + corsOrigins: [ + '*' + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + name: 'az-dicom-x-001' + publicNetworkAccess: 'Enabled' + workspaceName: 'hawmax001' + } +] +param fhirservices = [ + { + corsAllowCredentials: false + corsHeaders: [ + '*' + ] + corsMaxAge: 600 + corsMethods: [ + 'GET' + ] + corsOrigins: [ + '*' + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + importEnabled: false + initialImportMode: false + kind: 'fhir-R4' + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + name: 'az-fhir-x-001' + publicNetworkAccess: 'Enabled' + resourceVersionPolicy: 'versioned' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + smartProxyEnabled: false + workspaceName: 'hawmax001' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicNetworkAccess = 'Enabled' +param roleAssignments = [ + { + name: '6bfff821-2b18-4790-89fa-2849d86bc6be' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -438,7 +599,7 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -467,6 +628,27 @@ module workspace 'br/public:avm/res/healthcare-apis/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/healthcare-apis/workspace:' + +// Required parameters +param name = 'hawwaf001' +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -590,6 +772,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DICOM Data Owner'` + - `'DICOM Data Reader'` + - `'FHIR Data Contributor'` + - `'FHIR Data Converter'` + - `'FHIR Data Exporter'` + - `'FHIR Data Importer'` + - `'FHIR Data Reader'` + - `'FHIR Data Writer'` + - `'FHIR SMART User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/healthcare-apis/workspace/fhirservice/README.md b/avm/res/healthcare-apis/workspace/fhirservice/README.md index 0835f81584..ce0990cf46 100644 --- a/avm/res/healthcare-apis/workspace/fhirservice/README.md +++ b/avm/res/healthcare-apis/workspace/fhirservice/README.md @@ -468,6 +468,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DICOM Data Owner'` + - `'DICOM Data Reader'` + - `'FHIR Data Contributor'` + - `'FHIR Data Converter'` + - `'FHIR Data Exporter'` + - `'FHIR Data Importer'` + - `'FHIR Data Reader'` + - `'FHIR Data Writer'` + - `'FHIR SMART User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/hybrid-compute/machine/README.md b/avm/res/hybrid-compute/machine/README.md index 5221e3578b..2ad193517d 100644 --- a/avm/res/hybrid-compute/machine/README.md +++ b/avm/res/hybrid-compute/machine/README.md @@ -59,7 +59,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'HCI' +param name = 'arcmachcimin' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Creates an Arc Machine with maximum configurations_ This instance deploys the module with most of its features enabled. @@ -143,7 +160,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -212,6 +229,55 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'HCI' +param name = 'arcmachcimx' +// Non-required parameters +param guestConfiguration = { + assignmentType: 'ApplyAndMonitor' + configurationParameter: [ + { + name: 'Minimum Password Length;ExpectedValue' + value: '16' + } + { + name: 'Minimum Password Length;RemediateValue' + value: '16' + } + { + name: 'Maximum Password Age;ExpectedValue' + value: '75' + } + { + name: 'Maximum Password Age;RemediateValue' + value: '75' + } + ] + name: 'AzureWindowsBaseline' + version: '1.*' +} +param location = '' +param osType = 'Windows' +param patchAssessmentMode = 'AutomaticByPlatform' +param patchMode = 'AutomaticByPlatform' +param privateLinkScopeResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Creates an VMWare machine using only the defaults_ This instance deploys the module with the minimum set of required parameters. @@ -239,7 +305,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -264,6 +330,23 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'VMware' +param name = 'arcmacvmwmin' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -296,7 +379,7 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +411,28 @@ module machine 'br/public:avm/res/hybrid-compute/machine:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/hybrid-compute/machine:' + +// Required parameters +param kind = 'HCI' +param name = 'arcmacwaf' +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -509,6 +614,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Arc machine Administrator Login'` + - `'Arc machine Contributor'` + - `'Arc machine User Login'` + - `'Windows Admin Center Administrator Login'` **Required parameters** diff --git a/avm/res/insights/action-group/README.md b/avm/res/insights/action-group/README.md index 5ca2f832b8..6d443eba38 100644 --- a/avm/res/insights/action-group/README.md +++ b/avm/res/insights/action-group/README.md @@ -56,7 +56,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,23 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/action-group:' + +// Required parameters +param groupShortName = 'agiagmin001' +param name = 'iagmin001' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -151,7 +168,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +244,66 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/action-group:' + +// Required parameters +param groupShortName = 'agiagmax001' +param name = 'iagmax001' +// Non-required parameters +param emailReceivers = [ + { + emailAddress: 'test.user@testcompany.com' + name: 'TestUser_-EmailAction-' + useCommonAlertSchema: true + } + { + emailAddress: 'test.user2@testcompany.com' + name: 'TestUser2' + useCommonAlertSchema: true + } +] +param location = 'global' +param roleAssignments = [ + { + name: 'fc3ee4d9-d0c0-42c2-962f-082cf8d78882' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param smsReceivers = [ + { + countryCode: '1' + name: 'TestUser_-SMSAction-' + phoneNumber: '2345678901' + } +] +param tags = { + 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. @@ -259,7 +336,7 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -291,6 +368,28 @@ module actionGroup 'br/public:avm/res/insights/action-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/action-group:' + +// Required parameters +param groupShortName = 'agiagwaf001' +param name = 'iagwaf001' +// Non-required parameters +param location = 'global' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -413,6 +512,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/activity-log-alert/README.md b/avm/res/insights/activity-log-alert/README.md index ab8e82e305..8a307f678d 100644 --- a/avm/res/insights/activity-log-alert/README.md +++ b/avm/res/insights/activity-log-alert/README.md @@ -85,7 +85,7 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -139,6 +139,52 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/activity-log-alert:' + +// Required parameters +param conditions = [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Storage' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } +] +param name = 'ialamin001' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -229,7 +275,7 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -325,6 +371,86 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/activity-log-alert:' + +// Required parameters +param conditions = [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'Global' + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } +] +param name = 'ialamax001' +// Non-required parameters +param actions = [ + { + actionGroupId: '' + } +] +param location = 'global' +param roleAssignments = [ + { + name: 'be96d7a9-6596-40c7-9acd-db6acd5cd41b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scopes = [ + '' +] +param tags = { + 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. @@ -396,7 +522,7 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -471,6 +597,67 @@ module activityLogAlert 'br/public:avm/res/insights/activity-log-alert:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/activity-log-alert:' + +// Required parameters +param conditions = [ + { + equals: 'ServiceHealth' + field: 'category' + } + { + anyOf: [ + { + equals: 'Incident' + field: 'properties.incidentType' + } + { + equals: 'Maintenance' + field: 'properties.incidentType' + } + ] + } + { + containsAny: [ + 'Action Groups' + 'Activity Logs & Alerts' + ] + field: 'properties.impactedServices[*].ServiceName' + } + { + containsAny: [ + 'Global' + 'West Europe' + ] + field: 'properties.impactedServices[*].ImpactedRegions[*].RegionName' + } +] +param name = 'ialawaf001' +// Non-required parameters +param actions = [ + { + actionGroupId: '' + } +] +param location = 'global' +param scopes = [ + '' +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -553,6 +740,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/component/README.md b/avm/res/insights/component/README.md index 458098b208..5d3c5bd464 100644 --- a/avm/res/insights/component/README.md +++ b/avm/res/insights/component/README.md @@ -58,7 +58,7 @@ module component 'br/public:avm/res/insights/component:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -83,6 +83,23 @@ module component 'br/public:avm/res/insights/component:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/component:' + +// Required parameters +param name = 'icmin001' +param workspaceResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -152,7 +169,7 @@ module component 'br/public:avm/res/insights/component:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -233,6 +250,65 @@ module component 'br/public:avm/res/insights/component:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/component:' + +// Required parameters +param name = 'icmax001' +param workspaceResourceId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableIpMasking = false +param disableLocalAuth = true +param forceCustomerStorageForProfiler = true +param linkedStorageAccountResourceId = '' +param location = '' +param roleAssignments = [ + { + name: '8aacced3-3fce-41bc-a416-959df1acec57' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -279,7 +355,7 @@ module component 'br/public:avm/res/insights/component:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -327,6 +403,42 @@ module component 'br/public:avm/res/insights/component:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/component:' + +// Required parameters +param name = 'icwaf001' +param workspaceResourceId = '' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -645,6 +757,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Monitoring Metrics Publisher'` + - `'Application Insights Component Contributor'` + - `'Application Insights Snapshot Debugger'` + - `'Monitoring Contributor'` **Required parameters** diff --git a/avm/res/insights/data-collection-endpoint/README.md b/avm/res/insights/data-collection-endpoint/README.md index a1cd20427a..f84c7e1926 100644 --- a/avm/res/insights/data-collection-endpoint/README.md +++ b/avm/res/insights/data-collection-endpoint/README.md @@ -56,7 +56,7 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-endpoint:' + +// Required parameters +param name = 'idcemin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -135,7 +151,7 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -200,6 +216,53 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-endpoint:' + +// Required parameters +param name = 'idcemax001' +// Non-required parameters +param description = 'This is a test data collection endpoint.' +param kind = 'Windows' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicNetworkAccess = 'Enabled' +param roleAssignments = [ + { + name: 'db496446-89ac-4d91-a189-71544de0150a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -233,7 +296,7 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -268,6 +331,29 @@ module dataCollectionEndpoint 'br/public:avm/res/insights/data-collection-endpoi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-endpoint:' + +// Required parameters +param name = 'idcewaf001' +// Non-required parameters +param kind = 'Windows' +param location = '' +param publicNetworkAccess = 'Disabled' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -391,6 +477,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/data-collection-rule/README.md b/avm/res/insights/data-collection-rule/README.md index 6134656d6d..cc7b091211 100644 --- a/avm/res/insights/data-collection-rule/README.md +++ b/avm/res/insights/data-collection-rule/README.md @@ -74,7 +74,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -110,6 +110,34 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + agentSettings: { + logs: [ + { + name: 'MaxDiskQuotaInMB' + value: '5000' + } + ] + } + description: 'Agent Settings' + kind: 'AgentSettings' +} +param name = 'idcrags001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Collecting custom text logs with ingestion-time transformation_ This instance deploys the module to setup collection of custom logs and ingestion-time transformation. @@ -219,7 +247,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -330,6 +358,105 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableAdvanced_CL' + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + transformKql: 'source | extend LogFields = split(RawData, \',\') | extend EventTime = todatetime(LogFields[0]) | extend EventLevel = tostring(LogFields[1]) | extend EventCode = toint(LogFields[2]) | extend Message = tostring(LogFields[3]) | project TimeGenerated, EventTime, EventLevel, EventCode, Message' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsAdvanced\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableAdvanced_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableAdvanced_CL' + ] + } + ] + } + description: 'Collecting custom text logs with ingestion-time transformation to columns. Expected format of a log line (comma separated values): \',,,\', for example: \'2023-01-25T20:15:05Z,ERROR,404,Page not found\'' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + streamDeclarations: { + 'Custom-CustomTableAdvanced_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'EventTime' + type: 'datetime' + } + { + name: 'EventLevel' + type: 'string' + } + { + name: 'EventCode' + type: 'int' + } + { + name: 'Message' + type: 'string' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } +} +param name = 'idcrcusadv001' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true +} +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 3: _Collecting custom text logs_ This instance deploys the module to setup collection of custom logs. @@ -420,7 +547,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -510,6 +637,86 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableBasic_CL' + streams: [ + 'Custom-CustomTableBasic_CL' + ] + transformKql: 'source' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableBasic_CL' + ] + } + ] + } + description: 'Collecting custom text logs without ingestion-time transformation.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'All' + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } +} +param name = 'idcrcusbas001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 4: _Collecting IIS logs_ This instance deploys the module to setup the collection of IIS logs. @@ -579,7 +786,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -648,6 +855,65 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Microsoft-W3CIISLog' + streams: [ + 'Microsoft-W3CIISLog' + ] + transformKql: 'source' + } + ] + dataSources: { + iisLogs: [ + { + logDirectories: [ + 'C:\\inetpub\\logs\\LogFiles\\W3SVC1' + ] + name: 'iisLogsDataSource' + streams: [ + 'Microsoft-W3CIISLog' + ] + } + ] + } + description: 'Collecting IIS logs.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' +} +param name = 'idcrcusiis001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 5: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -715,7 +981,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -780,6 +1046,63 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + } + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + } + kind: 'Windows' +} +param name = 'idcrmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 6: _Collecting Linux-specific information_ This instance deploys the module to setup the collection of Linux-specific performance counters and Linux Syslog. @@ -962,7 +1285,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1144,6 +1467,178 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Syslog' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + 'Logical Disk(*)\\% Free Inodes' + 'Logical Disk(*)\\% Free Space' + 'Logical Disk(*)\\% Used Inodes' + 'Logical Disk(*)\\% Used Space' + 'Logical Disk(*)\\Disk Read Bytes/sec' + 'Logical Disk(*)\\Disk Reads/sec' + 'Logical Disk(*)\\Disk Transfers/sec' + 'Logical Disk(*)\\Disk Write Bytes/sec' + 'Logical Disk(*)\\Disk Writes/sec' + 'Logical Disk(*)\\Free Megabytes' + 'Logical Disk(*)\\Logical Disk Bytes/sec' + 'Memory(*)\\% Available Memory' + 'Memory(*)\\% Available Swap Space' + 'Memory(*)\\% Used Memory' + 'Memory(*)\\% Used Swap Space' + 'Memory(*)\\Available MBytes Memory' + 'Memory(*)\\Available MBytes Swap' + 'Memory(*)\\Page Reads/sec' + 'Memory(*)\\Page Writes/sec' + 'Memory(*)\\Pages/sec' + 'Memory(*)\\Used MBytes Swap Space' + 'Memory(*)\\Used Memory MBytes' + 'Network(*)\\Total Bytes' + 'Network(*)\\Total Bytes Received' + 'Network(*)\\Total Bytes Transmitted' + 'Network(*)\\Total Collisions' + 'Network(*)\\Total Packets Received' + 'Network(*)\\Total Packets Transmitted' + 'Network(*)\\Total Rx Errors' + 'Network(*)\\Total Tx Errors' + 'Processor(*)\\% DPC Time' + 'Processor(*)\\% Idle Time' + 'Processor(*)\\% Interrupt Time' + 'Processor(*)\\% IO Wait Time' + 'Processor(*)\\% Nice Time' + 'Processor(*)\\% Privileged Time' + 'Processor(*)\\% Processor Time' + 'Processor(*)\\% User Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + syslog: [ + { + facilityNames: [ + 'auth' + 'authpriv' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Debug' + 'Emergency' + 'Error' + 'Info' + 'Notice' + 'Warning' + ] + name: 'sysLogsDataSource-debugLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + { + facilityNames: [ + 'cron' + 'daemon' + 'kern' + 'local0' + 'mark' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Emergency' + 'Error' + 'Warning' + ] + name: 'sysLogsDataSource-warningLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + { + facilityNames: [ + 'local1' + 'local2' + 'local3' + 'local4' + 'local5' + 'local6' + 'local7' + 'lpr' + 'mail' + 'news' + 'syslog' + ] + logLevels: [ + 'Alert' + 'Critical' + 'Emergency' + 'Error' + ] + name: 'sysLogsDataSource-errLevel' + streams: [ + 'Microsoft-Syslog' + ] + } + ] + } + description: 'Collecting Linux-specific performance counters and Linux Syslog' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Linux' +} +param name = 'idcrlin001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Linux' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 7: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -1263,7 +1758,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1388,6 +1883,115 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataCollectionEndpointResourceId: '' + dataFlows: [ + { + destinations: [ + '' + ] + outputStream: 'Custom-CustomTableBasic_CL' + streams: [ + 'Custom-CustomTableBasic_CL' + ] + transformKql: 'source' + } + ] + dataSources: { + logFiles: [ + { + filePatterns: [ + 'C:\\TestLogsBasic\\TestLog*.log' + ] + format: 'text' + name: 'CustomTableBasic_CL' + samplingFrequencyInSeconds: 60 + settings: { + text: { + recordStartTimestampFormat: 'ISO 8601' + } + } + streams: [ + 'Custom-CustomTableBasic_CL' + ] + } + ] + } + description: 'Collecting custom text logs without ingestion-time transformation.' + destinations: { + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' + streamDeclarations: { + 'Custom-CustomTableBasic_CL': { + columns: [ + { + name: 'TimeGenerated' + type: 'datetime' + } + { + name: 'RawData' + type: 'string' + } + ] + } + } +} +param name = 'idcrmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '89a4d6fa-defb-4099-9196-173d94b91d67' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 8: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1524,7 +2128,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1660,6 +2264,132 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Event' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Page Faults/sec' + '\\Memory\\Pages/sec' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' +} +param name = 'idcrwaf001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ### Example 9: _Collecting Windows-specific information_ This instance deploys the module to setup the connection of Windows-specific performance counters and Windows Event Logs. @@ -1796,7 +2526,7 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1932,6 +2662,132 @@ module dataCollectionRule 'br/public:avm/res/insights/data-collection-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/data-collection-rule:' + +// Required parameters +param dataCollectionRuleProperties = { + dataFlows: [ + { + destinations: [ + 'azureMonitorMetrics-default' + ] + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + { + destinations: [ + '' + ] + streams: [ + 'Microsoft-Event' + ] + } + ] + dataSources: { + performanceCounters: [ + { + counterSpecifiers: [ + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Page Faults/sec' + '\\Memory\\Pages/sec' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Process(_Total)\\Handle Count' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Context Switches/sec' + '\\System\\Processes' + '\\System\\Processor Queue Length' + '\\System\\System Up Time' + ] + name: 'perfCounterDataSource60' + samplingFrequencyInSeconds: 60 + streams: [ + 'Microsoft-InsightsMetrics' + ] + } + ] + windowsEventLogs: [ + { + name: 'eventLogsDataSource' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Application!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + 'Security!*[System[(band(Keywords,13510798882111488))]]' + 'System!*[System[(Level=1 or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)]]' + ] + } + ] + } + description: 'Collecting Windows-specific performance counters and Windows Event Logs' + destinations: { + azureMonitorMetrics: { + name: 'azureMonitorMetrics-default' + } + logAnalytics: [ + { + name: '' + workspaceResourceId: '' + } + ] + } + kind: 'Windows' +} +param name = 'idcrwin001' +// Non-required parameters +param location = '' +param tags = { + 'hidden-title': 'This is visible in the resource name' + kind: 'Windows' + resourceType: 'Data Collection Rules' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2052,6 +2908,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/diagnostic-setting/README.md b/avm/res/insights/diagnostic-setting/README.md index 21e1fae6f8..17ab873d61 100644 --- a/avm/res/insights/diagnostic-setting/README.md +++ b/avm/res/insights/diagnostic-setting/README.md @@ -53,7 +53,7 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -76,6 +76,21 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/diagnostic-setting:' + +param location = '' +param name = 'idsmin001' +param workspaceResourceId = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -109,7 +124,7 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -148,6 +163,29 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/diagnostic-setting:' + +param eventHubAuthorizationRuleResourceId = '' +param eventHubName = '' +param location = '' +param metricCategories = [ + { + category: 'AllMetrics' + } +] +param name = 'idsmax001' +param storageAccountResourceId = '' +param workspaceResourceId = '' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -181,7 +219,7 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -220,6 +258,29 @@ module diagnosticSetting 'br/public:avm/res/insights/diagnostic-setting:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/diagnostic-setting:' + +param eventHubAuthorizationRuleResourceId = '' +param eventHubName = '' +param location = '' +param metricCategories = [ + { + category: 'AllMetrics' + } +] +param name = 'idswaf001' +param storageAccountResourceId = '' +param workspaceResourceId = '' +``` + +
    +

    + ## Parameters **Optional parameters** diff --git a/avm/res/insights/metric-alert/README.md b/avm/res/insights/metric-alert/README.md index a28a379fae..6f390fc6c6 100644 --- a/avm/res/insights/metric-alert/README.md +++ b/avm/res/insights/metric-alert/README.md @@ -72,7 +72,7 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -115,6 +115,39 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/metric-alert:' + +// Required parameters +param criteria = { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + dimensions: [] + metricName: 'Percentage CPU' + name: '1st criterion' + operator: 'GreaterThan' + threshold: 80 + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' +} +param name = 'imamin001' +// Non-required parameters +param location = 'Global' +param scopes = [ + '' +] +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -185,7 +218,7 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -265,6 +298,66 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/metric-alert:' + +// Required parameters +param criteria = { + allof: [ + { + criterionType: 'StaticThresholdCriterion' + metricName: 'Percentage CPU' + metricNamespace: 'microsoft.compute/virtualmachines' + name: 'HighCPU' + operator: 'GreaterThan' + threshold: '90' + timeAggregation: 'Average' + } + ] + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' +} +param name = 'imamax001' +// Non-required parameters +param actions = [ + '' +] +param location = 'Global' +param roleAssignments = [ + { + name: '3ab52119-85d9-4374-a454-2410b84f19f9' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param targetResourceRegion = 'westeurope' +param targetResourceType = 'microsoft.compute/virtualmachines' +param windowSize = 'PT15M' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -311,7 +404,7 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -365,6 +458,42 @@ module metricAlert 'br/public:avm/res/insights/metric-alert:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/metric-alert:' + +// Required parameters +param criteria = { + componentResourceId: '' + failedLocationCount: 3 + 'odata.type': 'Microsoft.Azure.Monitor.WebtestLocationAvailabilityCriteria' + webTestResourceId: '' +} +param name = 'imawaf001' +// Non-required parameters +param actions = [ + '' +] +param evaluationFrequency = 'PT5M' +param location = 'global' +param scopes = [ + '' + '' +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param windowSize = 'PT5M' +``` + +
    +

    + ## Parameters **Required parameters** @@ -498,6 +627,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/private-link-scope/README.md b/avm/res/insights/private-link-scope/README.md index 9c6f5d5719..82c8c5da93 100644 --- a/avm/res/insights/private-link-scope/README.md +++ b/avm/res/insights/private-link-scope/README.md @@ -60,7 +60,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/private-link-scope:' + +// Required parameters +param name = 'iplsmin001' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -269,7 +285,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -464,6 +480,183 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/private-link-scope:' + +// Required parameters +param name = 'iplsmax001' +// Non-required parameters +param accessModeSettings = { + exclusions: [ + { + ingestionAccessMode: 'PrivateOnly' + privateEndpointConnectionName: 'thisisatest' + queryAccessMode: 'PrivateOnly' + } + ] + ingestionAccessMode: 'Open' + queryAccessMode: 'Open' +} +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + customNetworkInterfaceName: 'nic-pe-' + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.19' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.20' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.21' + } + } + ] + name: 'pe-' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: 'af62023f-9f34-4bc0-8f05-2374886daf28' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scopedResources = [ + { + linkedResourceId: '' + name: 'scoped1' + } +] +param tags = { + 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. @@ -610,7 +803,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -758,6 +951,142 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/private-link-scope:' + +// Required parameters +param name = 'iplswaf001' +// Non-required parameters +param location = 'global' +param privateEndpoints = [ + { + customNetworkInterfaceName: 'nic-pe-' + ipConfigurations: [ + { + name: 'api' + properties: { + groupId: 'azuremonitor' + memberName: 'api' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'globalinai' + properties: { + groupId: 'azuremonitor' + memberName: 'global.in.ai' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'profiler' + properties: { + groupId: 'azuremonitor' + memberName: 'profiler' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'live' + properties: { + groupId: 'azuremonitor' + memberName: 'live' + privateIPAddress: '10.0.0.14' + } + } + { + name: 'diagservicesquery' + properties: { + groupId: 'azuremonitor' + memberName: 'diagservicesquery' + privateIPAddress: '10.0.0.15' + } + } + { + name: 'snapshot' + properties: { + groupId: 'azuremonitor' + memberName: 'snapshot' + privateIPAddress: '10.0.0.16' + } + } + { + name: 'agentsolutionpackstore' + properties: { + groupId: 'azuremonitor' + memberName: 'agentsolutionpackstore' + privateIPAddress: '10.0.0.17' + } + } + { + name: 'dce-global' + properties: { + groupId: 'azuremonitor' + memberName: 'dce-global' + privateIPAddress: '10.0.0.18' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.19' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.20' + } + } + { + name: '' + properties: { + groupId: 'azuremonitor' + memberName: '' + privateIPAddress: '10.0.0.21' + } + } + ] + name: 'pe-' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param scopedResources = [ + { + linkedResourceId: '' + name: 'scoped1' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -770,7 +1099,7 @@ module privateLinkScope 'br/public:avm/res/insights/private-link-scope: | Parameter | Type | Description | | :-- | :-- | :-- | -| [`accessModeSettings`](#parameter-accessmodesettings) | object | Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.

    * Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.

    * Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode. | +| [`accessModeSettings`](#parameter-accessmodesettings) | object | Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.

    * Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.

    * Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`location`](#parameter-location) | string | The location of the private link scope. Should be global. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | @@ -788,7 +1117,7 @@ Name of the private link scope. ### Parameter: `accessModeSettings` -Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.

    * Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.

    * Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode. +Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.

    * Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.

    * Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode. - Required: No - Type: object @@ -1221,6 +1550,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1332,6 +1672,21 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Logic App Contributor'` + - `'Monitoring Contributor'` + - `'Monitoring Metrics Publisher'` + - `'Monitoring Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Tag Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/private-link-scope/main.bicep b/avm/res/insights/private-link-scope/main.bicep index 50534b0383..a6666eec33 100644 --- a/avm/res/insights/private-link-scope/main.bicep +++ b/avm/res/insights/private-link-scope/main.bicep @@ -203,6 +203,9 @@ module privateLinkScope_privateEndpoints 'br/public:avm/res/network/private-endp applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName } + dependsOn: [ + privateLinkScope_scopedResource + ] } ] diff --git a/avm/res/insights/private-link-scope/main.json b/avm/res/insights/private-link-scope/main.json index c1efbd235d..ecb92303a1 100644 --- a/avm/res/insights/private-link-scope/main.json +++ b/avm/res/insights/private-link-scope/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9210191494689145931" + "version": "0.30.3.12046", + "templateHash": "5947451992668490696" }, "name": "Azure Monitor Private Link Scopes", "description": "This module deploys an Azure Monitor Private Link Scope.", @@ -430,7 +430,7 @@ "accessModeSettings": { "$ref": "#/definitions/accessModeType", "metadata": { - "description": "Optional. Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.\n\n * Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.\n * Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode." + "description": "Optional. Specifies the access mode of ingestion or queries through associated private endpoints in scope. For security reasons, it is recommended to use PrivateOnly whenever possible to avoid data exfiltration.\n\n* Private Only - This mode allows the connected virtual network to reach only Private Link resources. It is the most secure mode and is set as the default when the `privateEndpoints` parameter is configured.\n* Open - Allows the connected virtual network to reach both Private Link resources and the resources not in the AMPLS resource. Data exfiltration cannot be prevented in this mode." } }, "location": { @@ -601,8 +601,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15704480901641345186" + "version": "0.30.3.12046", + "templateHash": "16277811786602972091" }, "name": "Private Link Scope Scoped Resources", "description": "This module deploys a Private Link Scope Scoped Resource.", @@ -1432,7 +1432,8 @@ } }, "dependsOn": [ - "privateLinkScope" + "privateLinkScope", + "privateLinkScope_scopedResource" ] } }, diff --git a/avm/res/insights/private-link-scope/scoped-resource/main.json b/avm/res/insights/private-link-scope/scoped-resource/main.json index 57e0b76f73..430361afb5 100644 --- a/avm/res/insights/private-link-scope/scoped-resource/main.json +++ b/avm/res/insights/private-link-scope/scoped-resource/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15704480901641345186" + "version": "0.30.3.12046", + "templateHash": "16277811786602972091" }, "name": "Private Link Scope Scoped Resources", "description": "This module deploys a Private Link Scope Scoped Resource.", diff --git a/avm/res/insights/scheduled-query-rule/README.md b/avm/res/insights/scheduled-query-rule/README.md index c0f4c7a979..617dc4cecc 100644 --- a/avm/res/insights/scheduled-query-rule/README.md +++ b/avm/res/insights/scheduled-query-rule/README.md @@ -87,7 +87,7 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -149,6 +149,54 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/scheduled-query-rule:' + +// Required parameters +param criterias = { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] +} +param name = 'isqrmin001' +param scopes = [ + '' +] +// Non-required parameters +param evaluationFrequency = 'PT5M' +param location = '' +param windowSize = 'PT5M' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -240,7 +288,7 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -351,6 +399,87 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/scheduled-query-rule:' + +// Required parameters +param criterias = { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] +} +param name = 'isqrmax001' +param scopes = [ + '' +] +// Non-required parameters +param alertDescription = 'My sample Alert' +param alertDisplayName = '' +param autoMitigate = false +param evaluationFrequency = 'PT5M' +param location = '' +param queryTimeRange = 'PT5M' +param roleAssignments = [ + { + name: 'fa8868c7-33d3-4cd5-86a5-cbf76261035b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param ruleResolveConfiguration = { + autoResolved: true + timeToResolve: 'PT5M' +} +param suppressForMinutes = 'PT5M' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param windowSize = 'PT5M' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -418,7 +547,7 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -499,6 +628,63 @@ module scheduledQueryRule 'br/public:avm/res/insights/scheduled-query-rule:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/scheduled-query-rule:' + +// Required parameters +param criterias = { + allOf: [ + { + dimensions: [ + { + name: 'Computer' + operator: 'Include' + values: [ + '*' + ] + } + { + name: 'InstanceName' + operator: 'Include' + values: [ + '*' + ] + } + ] + metricMeasureColumn: 'AggregatedValue' + operator: 'GreaterThan' + query: 'Perf | where ObjectName == \'LogicalDisk\' | where CounterName == \'% Free Space\' | where InstanceName <> \'HarddiskVolume1\' and InstanceName <> \'_Total\' | summarize AggregatedValue = min(CounterValue) by Computer, InstanceName, bin(TimeGenerated,5m)' + threshold: 0 + timeAggregation: 'Average' + } + ] +} +param name = 'isqrwaf001' +param scopes = [ + '' +] +// Non-required parameters +param alertDescription = 'My sample Alert' +param autoMitigate = false +param evaluationFrequency = 'PT5M' +param location = '' +param queryTimeRange = 'PT5M' +param suppressForMinutes = 'PT5M' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param windowSize = 'PT5M' +``` + +
    +

    + ## Parameters **Required parameters** @@ -658,6 +844,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/insights/webtest/README.md b/avm/res/insights/webtest/README.md index 2b0ca9def0..f9f5197cd4 100644 --- a/avm/res/insights/webtest/README.md +++ b/avm/res/insights/webtest/README.md @@ -62,7 +62,7 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -96,6 +96,28 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/webtest:' + +// Required parameters +param appInsightResourceId = '' +param name = 'iwtmin001' +param request = { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' +} +param webTestName = 'wt$iwtmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -162,7 +184,7 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -240,6 +262,62 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/webtest:' + +// Required parameters +param appInsightResourceId = '' +param name = 'iwtmax001' +param request = { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' +} +param webTestName = 'wt$iwtmax001' +// Non-required parameters +param location = '' +param locations = [ + { + Id: 'emea-nl-ams-azr' + } +] +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '86bf66a0-940f-438d-977e-624c00ccb2d8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param syntheticMonitorId = 'iwtmax001' +param tags = { + 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. @@ -281,7 +359,7 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -330,6 +408,37 @@ module webtest 'br/public:avm/res/insights/webtest:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/insights/webtest:' + +// Required parameters +param appInsightResourceId = '' +param name = 'iwtwaf001' +param request = { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' +} +param webTestName = 'wt$iwtwaf001' +// Non-required parameters +param location = '' +param locations = [ + { + Id: 'emea-nl-ams-azr' + } +] +param syntheticMonitorId = 'iwtwaf001' +param tags = { + 'hidden-title': 'This is visible in the resource name' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -529,6 +638,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 10326e55cc..880c933a5f 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -66,7 +66,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -91,6 +91,23 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvmin002' +// Non-required parameters +param enablePurgeProtection = false +param location = '' +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -152,7 +169,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -213,6 +230,57 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvec002' +// Non-required parameters +param enablePurgeProtection = false +param enableRbacAuthorization = true +param keys = [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + kty: 'EC' + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +param location = '' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -466,7 +534,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -737,6 +805,249 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvmax002' +// Non-required parameters +param accessPolicies = [ + { + objectId: '' + permissions: { + keys: [ + 'get' + 'list' + 'update' + ] + secrets: [ + 'all' + ] + } + tenantId: '' + } + { + objectId: '' + permissions: { + certificates: [ + 'backup' + 'create' + 'delete' + ] + secrets: [ + 'all' + ] + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'AzurePolicyEvaluationDetails' + } + { + category: 'AuditEvent' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enablePurgeProtection = false +param enableRbacAuthorization = false +param keys = [ + { + attributesExp: 1725109032 + attributesNbf: 10000 + name: 'keyName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + value: '40.74.28.0/23' + } + ] + virtualNetworkRules: [ + { + id: '' + ignoreMissingVnetServiceEndpoint: false + } + ] +} +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'b50cc72e-a2f2-4c4c-a3ad-86a43feb6ab8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param secrets = [ + { + attributesExp: 1702648632 + attributesNbf: 10000 + contentType: 'Something' + name: 'secretName' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + value: 'secretValue' + } +] +param softDeleteRetentionInDays = 7 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -798,7 +1109,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -859,6 +1170,57 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvrsa002' +// Non-required parameters +param enablePurgeProtection = false +param enableRbacAuthorization = true +param keys = [ + { + attributes: { + exp: 1725109032 + nbf: 10000 + } + kty: 'RSA' + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +param location = '' +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -968,7 +1330,7 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1091,6 +1453,105 @@ module vault 'br/public:avm/res/key-vault/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/key-vault/vault:' + +// Required parameters +param name = 'kvvwaf002' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enablePurgeProtection = false +param enableRbacAuthorization = true +param keys = [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + keySize: 4096 + name: 'keyName' + rotationPolicy: { + attributes: { + expiryTime: 'P2Y' + } + lifetimeActions: [ + { + action: { + type: 'Rotate' + } + trigger: { + timeBeforeExpiry: 'P2M' + } + } + { + action: { + type: 'Notify' + } + trigger: { + timeBeforeExpiry: 'P30D' + } + } + ] + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'vault' + subnetResourceId: '' + } +] +param secrets = [ + { + attributes: { + enabled: true + exp: 1702648632 + nbf: 10000 + } + contentType: 'Something' + name: 'secretName' + value: 'secretValue' + } +] +param softDeleteRetentionInDays = 7 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1681,6 +2142,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2223,6 +2696,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2350,6 +2834,22 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Certificates Officer'` + - `'Key Vault Certificate User'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2527,6 +3027,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/key/README.md b/avm/res/key-vault/vault/key/README.md index 4531fa3eab..a5dfe17fe2 100644 --- a/avm/res/key-vault/vault/key/README.md +++ b/avm/res/key-vault/vault/key/README.md @@ -154,6 +154,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Crypto Officer'` + - `'Key Vault Crypto Service Encryption User'` + - `'Key Vault Crypto User'` + - `'Key Vault Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/key/main.bicep b/avm/res/key-vault/vault/key/main.bicep index 45e00bf511..5f54bc9464 100644 --- a/avm/res/key-vault/vault/key/main.bicep +++ b/avm/res/key-vault/vault/key/main.bicep @@ -129,8 +129,10 @@ resource key 'Microsoft.KeyVault/vaults/keys@2022-07-01' = { keyOps: keyOps keySize: keySize kty: kty - rotationPolicy: rotationPolicy ?? {} release_policy: releasePolicy ?? {} + ...(empty(rotationPolicy) ? {} : { + rotationPolicy: rotationPolicy + }) } } diff --git a/avm/res/key-vault/vault/key/main.json b/avm/res/key-vault/vault/key/main.json index 63c2159cb2..6976827555 100644 --- a/avm/res/key-vault/vault/key/main.json +++ b/avm/res/key-vault/vault/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14269695922191217406" + "version": "0.30.3.12046", + "templateHash": "13039550242026782790" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -232,19 +232,7 @@ "apiVersion": "2022-07-01", "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", "tags": "[parameters('tags')]", - "properties": { - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "curveName": "[parameters('curveName')]", - "keyOps": "[parameters('keyOps')]", - "keySize": "[parameters('keySize')]", - "kty": "[parameters('kty')]", - "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", - "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" - }, + "properties": "[shallowMerge(createArray(createObject('attributes', createObject('enabled', parameters('attributesEnabled'), 'exp', parameters('attributesExp'), 'nbf', parameters('attributesNbf')), 'curveName', parameters('curveName'), 'keyOps', parameters('keyOps'), 'keySize', parameters('keySize'), 'kty', parameters('kty'), 'release_policy', coalesce(parameters('releasePolicy'), createObject())), if(empty(parameters('rotationPolicy')), createObject(), createObject('rotationPolicy', parameters('rotationPolicy')))))]", "dependsOn": [ "keyVault" ] diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 74ea3bdd03..a6769b9cb6 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8938543730613882040" + "version": "0.30.23.60470", + "templateHash": "4499855760252174192" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -1224,8 +1224,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7494731697751039419" + "version": "0.30.23.60470", + "templateHash": "15469258025112973480" }, "name": "Key Vault Access Policies", "description": "This module deploys a Key Vault Access Policy.", @@ -1493,8 +1493,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "114626909766354577" + "version": "0.30.23.60470", + "templateHash": "10121697157844029321" }, "name": "Key Vault Secrets", "description": "This module deploys a Key Vault Secret.", @@ -1791,8 +1791,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14269695922191217406" + "version": "0.30.23.60470", + "templateHash": "796741209006922272" }, "name": "Key Vault Keys", "description": "This module deploys a Key Vault Key.", @@ -2018,19 +2018,7 @@ "apiVersion": "2022-07-01", "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", "tags": "[parameters('tags')]", - "properties": { - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "curveName": "[parameters('curveName')]", - "keyOps": "[parameters('keyOps')]", - "keySize": "[parameters('keySize')]", - "kty": "[parameters('kty')]", - "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", - "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" - }, + "properties": "[shallowMerge(createArray(createObject('attributes', createObject('enabled', parameters('attributesEnabled'), 'exp', parameters('attributesExp'), 'nbf', parameters('attributesNbf')), 'curveName', parameters('curveName'), 'keyOps', parameters('keyOps'), 'keySize', parameters('keySize'), 'kty', parameters('kty'), 'release_policy', coalesce(parameters('releasePolicy'), createObject())), if(empty(parameters('rotationPolicy')), createObject(), createObject('rotationPolicy', parameters('rotationPolicy')))))]", "dependsOn": [ "keyVault" ] diff --git a/avm/res/key-vault/vault/secret/README.md b/avm/res/key-vault/vault/secret/README.md index d62aac35dd..b05c38071f 100644 --- a/avm/res/key-vault/vault/secret/README.md +++ b/avm/res/key-vault/vault/secret/README.md @@ -97,6 +97,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Key Vault Administrator'` + - `'Key Vault Contributor'` + - `'Key Vault Reader'` + - `'Key Vault Secrets Officer'` + - `'Key Vault Secrets User'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/key-vault/vault/version.json b/avm/res/key-vault/vault/version.json index b8b30a0125..9c08aae215 100644 --- a/avm/res/key-vault/vault/version.json +++ b/avm/res/key-vault/vault/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.9", + "version": "0.10", "pathFilters": [ "./main.json" ] diff --git a/avm/res/kubernetes-configuration/extension/README.md b/avm/res/kubernetes-configuration/extension/README.md index 8c9870da2e..2467e5fb16 100644 --- a/avm/res/kubernetes-configuration/extension/README.md +++ b/avm/res/kubernetes-configuration/extension/README.md @@ -61,7 +61,7 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -95,6 +95,26 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/extension:' + +// Required parameters +param clusterName = '' +param extensionType = 'microsoft.flux' +param name = 'kcemin001' +// Non-required parameters +param location = '' +param releaseNamespace = 'flux-system' +param releaseTrain = 'Stable' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -154,7 +174,7 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -223,6 +243,55 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/extension:' + +// Required parameters +param clusterName = '' +param extensionType = 'microsoft.flux' +param name = 'kcemax001' +// Non-required parameters +param configurationSettings = { + 'image-automation-controller.enabled': 'false' + 'image-reflector-controller.enabled': 'false' + 'kustomize-controller.enabled': 'true' + 'notification-controller.enabled': 'false' + 'source-controller.enabled': 'true' +} +param fluxConfigurations = [ + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' + } + kustomizations: { + unified: { + path: './cluster-manifests' + } + } + namespace: 'flux-system' + scope: 'cluster' + suspend: false + } +] +param location = '' +param releaseNamespace = 'flux-system' +param releaseTrain = 'Stable' +param version = '0.5.2' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -282,7 +351,7 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -351,6 +420,55 @@ module extension 'br/public:avm/res/kubernetes-configuration/extension:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/extension:' + +// Required parameters +param clusterName = '' +param extensionType = 'microsoft.flux' +param name = 'kcewaf001' +// Non-required parameters +param configurationSettings = { + 'image-automation-controller.enabled': 'false' + 'image-reflector-controller.enabled': 'false' + 'kustomize-controller.enabled': 'true' + 'notification-controller.enabled': 'false' + 'source-controller.enabled': 'true' +} +param fluxConfigurations = [ + { + gitRepository: { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' + } + kustomizations: { + unified: { + path: './cluster-manifests' + } + } + namespace: 'flux-system' + scope: 'cluster' + suspend: false + } +] +param location = '' +param releaseNamespace = 'flux-system' +param releaseTrain = 'Stable' +param version = '0.5.2' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/kubernetes-configuration/flux-configuration/README.md b/avm/res/kubernetes-configuration/flux-configuration/README.md index be9ed2ecb7..57c4931d74 100644 --- a/avm/res/kubernetes-configuration/flux-configuration/README.md +++ b/avm/res/kubernetes-configuration/flux-configuration/README.md @@ -73,7 +73,7 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

    -via JSON Parameter file +via JSON parameters file ```json { @@ -125,6 +125,40 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/flux-configuration:' + +// Required parameters +param clusterName = '' +param kustomizations = { + unified: { + path: './cluster-manifests' + } +} +param name = 'kcfcmin001' +param namespace = 'flux-system' +param scope = 'cluster' +param sourceKind = 'GitRepository' +// Non-required parameters +param gitRepository = { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' +} +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -180,7 +214,7 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

    -via JSON Parameter file +via JSON parameters file ```json { @@ -243,6 +277,51 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/flux-configuration:' + +// Required parameters +param clusterName = '' +param kustomizations = { + unified: { + dependsOn: [] + force: false + path: './cluster-manifests' + postBuild: { + substitute: { + TEST_VAR1: 'foo' + TEST_VAR2: 'bar' + } + } + prune: true + syncIntervalInSeconds: 300 + timeoutInSeconds: 300 + } +} +param name = 'kcfcmax001' +param namespace = 'flux-system' +param scope = 'cluster' +param sourceKind = 'GitRepository' +// Non-required parameters +param gitRepository = { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' +} +param location = '' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -292,7 +371,7 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

    -via JSON Parameter file +via JSON parameters file ```json { @@ -349,6 +428,45 @@ module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-config

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kubernetes-configuration/flux-configuration:' + +// Required parameters +param clusterName = '' +param kustomizations = { + unified: { + dependsOn: [] + force: false + path: './cluster-manifests' + prune: true + syncIntervalInSeconds: 300 + timeoutInSeconds: 300 + } +} +param name = 'kcfcwaf001' +param namespace = 'flux-system' +param scope = 'cluster' +param sourceKind = 'GitRepository' +// Non-required parameters +param gitRepository = { + repositoryRef: { + branch: 'main' + } + sshKnownHosts: '' + syncIntervalInSeconds: 300 + timeoutInSeconds: 180 + url: 'https://github.com/mspnp/aks-baseline' +} +param location = '' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/kusto/cluster/README.md b/avm/res/kusto/cluster/README.md index 8d94f1f46f..6c6e0b22ed 100644 --- a/avm/res/kusto/cluster/README.md +++ b/avm/res/kusto/cluster/README.md @@ -63,7 +63,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,23 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcmin0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -175,7 +192,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -302,6 +319,83 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcmax0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param acceptedAudiences = [ + { + value: 'https://contoso.com' + } +] +param allowedFqdnList = [ + 'contoso.com' +] +param allowedIpRangeList = [ + '192.168.1.1' +] +param autoScaleMax = 6 +param autoScaleMin = 3 +param capacity = 3 +param enableAutoScale = true +param enableAutoStop = true +param enableDiskEncryption = true +param enableDoubleEncryption = true +param enablePublicNetworkAccess = true +param enablePurge = true +param enableRestrictOutboundNetworkAccess = true +param enableStreamingIngest = true +param enableZoneRedundant = true +param engineType = 'V3' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param principalAssignments = [ + { + principalId: '' + principalType: 'Group' + role: 'AllDatabasesViewer' + } +] +param publicIPType = 'DualStack' +param roleAssignments = [ + { + name: 'c2a4b728-c3d0-47f5-afbb-ea45c45859de' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
    +

    + ### Example 3: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -360,7 +454,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -424,6 +518,54 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcpe0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param enablePublicNetworkAccess = false +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'cluster' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'cluster' + subnetResourceId: '' + } +] +param publicIPType = 'IPv4' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -474,7 +616,7 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -548,6 +690,46 @@ module cluster 'br/public:avm/res/kusto/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/kusto/cluster:' + +// Required parameters +param name = 'akcwaf0001' +param sku = 'Standard_E2ads_v5' +// Non-required parameters +param autoScaleMax = 10 +param autoScaleMin = 3 +param capacity = 3 +param enableAutoScale = true +param enableAutoStop = true +param enableDiskEncryption = true +param enableDoubleEncryption = true +param enablePublicNetworkAccess = false +param enableZoneRedundant = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param tier = 'Standard' +``` + +
    +

    + ## Parameters **Required parameters** @@ -1390,6 +1572,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1510,6 +1703,10 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` **Required parameters** diff --git a/avm/res/load-test-service/load-test/README.md b/avm/res/load-test-service/load-test/README.md index 16936f9cdf..f2d587f3a7 100644 --- a/avm/res/load-test-service/load-test/README.md +++ b/avm/res/load-test-service/load-test/README.md @@ -57,7 +57,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -136,7 +152,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -199,6 +215,53 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltmax001' +// Non-required parameters +param loadTestDescription = 'This is a test load test to validate the module.' +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + systemAssigned: true +} +param roleAssignments = [ + { + name: 'd37a15bc-8634-4f4f-a736-700c1b955cd7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -235,7 +298,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -271,6 +334,32 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltucmk001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -304,7 +393,7 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -339,6 +428,29 @@ module loadTest 'br/public:avm/res/load-test-service/load-test:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/load-test-service/load-test:' + +// Required parameters +param name = 'ltwaf001' +// Non-required parameters +param enableTelemetry = '' +param loadTestDescription = 'This is a sample load test.' +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -509,6 +621,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/logic/workflow/README.md b/avm/res/logic/workflow/README.md index fc08456b5c..9de770ef08 100644 --- a/avm/res/logic/workflow/README.md +++ b/avm/res/logic/workflow/README.md @@ -58,7 +58,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -80,6 +80,22 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/logic/workflow:' + +// Required parameters +param name = 'lwmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -184,7 +200,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -298,6 +314,100 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/logic/workflow:' + +// Required parameters +param name = 'lwmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '1f98c16b-ea00-4686-8b81-05353b594ea3' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param workflowActions = { + HTTP: { + inputs: { + body: { + BeginPeakTime: '' + EndPeakTime: '' + HostPoolName: '' + LAWorkspaceName: '' + LimitSecondsToForceLogOffUser: '' + LogOffMessageBody: '' + LogOffMessageTitle: '' + MinimumNumberOfRDSH: 1 + ResourceGroupName: '' + SessionThresholdPerCPU: 1 + UtcOffset: '' + } + method: 'POST' + uri: 'https://testStringForValidation.com' + } + type: 'Http' + } +} +param workflowTriggers = { + Recurrence: { + recurrence: { + frequency: 'Minute' + interval: 15 + } + type: 'Recurrence' + } +} +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -383,7 +493,7 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -476,6 +586,81 @@ module workflow 'br/public:avm/res/logic/workflow:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/logic/workflow:' + +// Required parameters +param name = 'lwwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param workflowActions = { + HTTP: { + inputs: { + body: { + BeginPeakTime: '' + EndPeakTime: '' + HostPoolName: '' + LAWorkspaceName: '' + LimitSecondsToForceLogOffUser: '' + LogOffMessageBody: '' + LogOffMessageTitle: '' + MinimumNumberOfRDSH: 1 + ResourceGroupName: '' + SessionThresholdPerCPU: 1 + UtcOffset: '' + } + method: 'POST' + uri: 'https://testStringForValidation.com' + } + type: 'Http' + } +} +param workflowTriggers = { + Recurrence: { + recurrence: { + frequency: 'Minute' + interval: 15 + } + type: 'Recurrence' + } +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -805,6 +990,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Logic App Contributor'` + - `'Logic App Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/machine-learning-services/workspace/README.md b/avm/res/machine-learning-services/workspace/README.md index 860f066e50..5257a24585 100644 --- a/avm/res/machine-learning-services/workspace/README.md +++ b/avm/res/machine-learning-services/workspace/README.md @@ -95,7 +95,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -160,6 +160,51 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswai001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param connections = [ + { + category: 'AIServices' + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: 'key' + } + } + metadata: { + ApiType: 'Azure' + ApiVersion: '2023-07-01-preview' + DeploymentApiVersion: '2023-10-01-preview' + Location: '' + ResourceId: '' + } + name: 'ai' + target: '' + } +] +param kind = 'Hub' +param location = '' +param workspaceHubConfig = { + additionalWorkspaceStorageAccounts: '' + defaultWorkspaceResourceGroup: '' +} +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -190,7 +235,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +269,26 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswmin001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param location = '' +``` + +
    +

    + ### Example 3: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -279,7 +344,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -346,6 +411,51 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswecr001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param managedNetworkSettings = { + isolationMode: 'AllowInternetOutbound' + outboundRules: { + rule: { + category: 'UserDefined' + destination: { + serviceResourceId: '' + subresourceTarget: 'blob' + } + type: 'PrivateEndpoint' + } + } +} +param primaryUserAssignedIdentity = '' +``` + +
    +

    + ### Example 4: _Creating Azure ML managed feature store_ This instance deploys an Azure ML managed feature store. @@ -382,7 +492,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -426,6 +536,32 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswfs001' +param sku = 'Basic' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param featureStoreSettings = { + computeRuntime: { + sparkRuntimeVersion: '3.3' + } +} +param kind = 'FeatureStore' +param location = '' +``` + +
    +

    + ### Example 5: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -591,7 +727,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -792,6 +928,161 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswmax001' +param sku = 'Premium' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param computes = [ + { + computeLocation: '' + computeType: 'AmlCompute' + description: 'Default CPU Cluster' + disableLocalAuth: false + location: '' + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] + } + name: 'DefaultCPU' + properties: { + enableNodePublicIp: true + isolatedNetwork: false + osType: 'Linux' + remoteLoginPortPublicAccess: 'Disabled' + scaleSettings: { + maxNodeCount: 3 + minNodeCount: 0 + nodeIdleTimeBeforeScaleDown: 'PT5M' + } + vmPriority: 'Dedicated' + vmSize: 'STANDARD_DS11_V2' + } + sku: 'Basic' + } +] +param connections = [ + { + category: 'ApiKey' + connectionProperties: { + authType: 'ApiKey' + credentials: { + key: 'key' + } + } + name: 'connection' + target: 'https://example.com' + } +] +param description = 'The cake is a lie.' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param discoveryUrl = 'http://example.com' +param imageBuildCompute = 'testcompute' +param kind = 'Default' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: false + userAssignedResourceIds: [ + '' + ] +} +param managedNetworkSettings = { + isolationMode: 'Disabled' +} +param primaryUserAssignedIdentity = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + name: 'group1' + privateDnsZoneGroupConfigs: [ + { + name: 'config1' + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + name: 'group2' + privateDnsZoneGroupConfigs: [ + { + name: 'config2' + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'f9b5b0d9-f27e-4c89-bacf-1bbc4a99dbce' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param serverlessComputeSettings = { + serverlessComputeCustomSubnet: '' + serverlessComputeNoPublicIP: true +} +param systemDatastoresAuthMode = 'accessKey' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -881,7 +1172,7 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -984,6 +1275,85 @@ module workspace 'br/public:avm/res/machine-learning-services/workspace:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/machine-learning-services/workspace:' + +// Required parameters +param name = 'mlswwaf001' +param sku = 'Standard' +// Non-required parameters +param associatedApplicationInsightsResourceId = '' +param associatedKeyVaultResourceId = '' +param associatedStorageAccountResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param managedNetworkSettings = { + isolationMode: 'AllowOnlyApprovedOutbound' + outboundRules: { + rule1: { + category: 'UserDefined' + destination: { + serviceResourceId: '' + sparkEnabled: true + subresourceTarget: 'blob' + } + type: 'PrivateEndpoint' + } + rule2: { + category: 'UserDefined' + destination: 'pypi.org' + type: 'FQDN' + } + rule3: { + category: 'UserDefined' + destination: { + portRanges: '80,443' + protocol: 'TCP' + serviceTag: 'AppService' + } + type: 'ServiceTag' + } + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param systemDatastoresAuthMode = 'identity' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2035,6 +2405,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2161,6 +2542,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'AzureML Compute Operator'` + - `'AzureML Data Scientist'` + - `'AzureML Metrics Writer (preview)'` + - `'AzureML Registry User'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/machine-learning-services/workspace/compute/main.json b/avm/res/machine-learning-services/workspace/compute/main.json index 24fa048bd0..c3832c8377 100644 --- a/avm/res/machine-learning-services/workspace/compute/main.json +++ b/avm/res/machine-learning-services/workspace/compute/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8580750401363518569" + "version": "0.30.23.60470", + "templateHash": "6461308246344228681" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", diff --git a/avm/res/machine-learning-services/workspace/connection/main.json b/avm/res/machine-learning-services/workspace/connection/main.json index 6e49f757aa..f4efdf611d 100644 --- a/avm/res/machine-learning-services/workspace/connection/main.json +++ b/avm/res/machine-learning-services/workspace/connection/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2277907099827503661" + "version": "0.30.23.60470", + "templateHash": "11897886685116125832" }, "name": "Machine Learning Services Workspaces Connections", "description": "This module creates a connection in a Machine Learning Services workspace.", diff --git a/avm/res/machine-learning-services/workspace/main.json b/avm/res/machine-learning-services/workspace/main.json index c90b0b9598..188ff7e44c 100644 --- a/avm/res/machine-learning-services/workspace/main.json +++ b/avm/res/machine-learning-services/workspace/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6210663004291725942" + "version": "0.30.23.60470", + "templateHash": "13428062064493278756" }, "name": "Machine Learning Services Workspaces", "description": "This module deploys a Machine Learning Services Workspace.", @@ -1981,8 +1981,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8580750401363518569" + "version": "0.30.23.60470", + "templateHash": "6461308246344228681" }, "name": "Machine Learning Services Workspaces Computes", "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", @@ -2244,8 +2244,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2277907099827503661" + "version": "0.30.23.60470", + "templateHash": "11897886685116125832" }, "name": "Machine Learning Services Workspaces Connections", "description": "This module creates a connection in a Machine Learning Services workspace.", diff --git a/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep b/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep index 7a7181129f..946aaa8d9a 100644 --- a/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep +++ b/avm/res/machine-learning-services/workspace/tests/e2e/encr/dependencies.bicep @@ -61,15 +61,42 @@ resource keyVaultServicePermissions 'Microsoft.Authorization/roleAssignments@202 principalType: 'ServicePrincipal' } } -resource keyVaultDataPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-KeyVault-Data-Admin-RoleAssignment') - scope: keyVault::key + +resource keyVaultAdminPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-KeyVault-Admin-RoleAssignment') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '00482a5a-887f-4fb3-b363-3b7fe8e74483' + ) // Key Vault Administrator + principalType: 'ServicePrincipal' + } +} + +resource keyVaultUserPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-KeyVault-Crypto-User-RoleAssignment') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e147488a-f6f5-4113-8e2d-b22465e65bf6' + ) // Key Vault Crypto Service Encryption User + principalType: 'ServicePrincipal' + } +} + +resource storageAccountPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${secondaryStorageAccount.id}-${location}-${managedIdentity.id}-StorageAccount-RoleAssignment') + scope: secondaryStorageAccount properties: { principalId: managedIdentity.properties.principalId roleDefinitionId: subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', - '12338af0-0e69-4776-bea7-57ae8d297424' - ) // Key Vault Crypto User + 'b556d68e-0be0-4f35-a333-ad7ee1ce17ea' + ) // Azure AI Enterprise Network Connection Approver principalType: 'ServicePrincipal' } } diff --git a/avm/res/maintenance/maintenance-configuration/README.md b/avm/res/maintenance/maintenance-configuration/README.md index b2fe74ff0c..a7e122c5da 100644 --- a/avm/res/maintenance/maintenance-configuration/README.md +++ b/avm/res/maintenance/maintenance-configuration/README.md @@ -56,7 +56,7 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/maintenance/maintenance-configuration:' + +// Required parameters +param name = 'mmcmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -161,7 +177,7 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +274,79 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/maintenance/maintenance-configuration:' + +// Required parameters +param name = 'mmcmax001' +// Non-required parameters +param extensionProperties = { + InGuestPatchMode: 'User' +} +param installPatches = { + linuxParameters: { + classificationsToInclude: '' + packageNameMasksToExclude: '' + packageNameMasksToInclude: '' + } + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + kbNumbersToExclude: '' + kbNumbersToInclude: '' + } +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maintenanceScope = 'InGuestPatch' +param maintenanceWindow = { + duration: '03:00' + expirationDateTime: '9999-12-31 23:59:59' + recurEvery: 'Day' + startDateTime: '2022-12-31 13:00' + timeZone: 'W. Europe Standard Time' +} +param namespace = 'mmcmaxns' +param roleAssignments = [ + { + name: 'd78ec5f7-4692-4f43-8c17-7569466bbed5' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = 'Custom' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -318,7 +407,7 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

    -via JSON Parameter file +via JSON parameters file ```json { @@ -388,6 +477,56 @@ module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-confi

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/maintenance/maintenance-configuration:' + +// Required parameters +param name = 'mmcwaf001' +// Non-required parameters +param extensionProperties = { + InGuestPatchMode: 'User' +} +param installPatches = { + linuxParameters: { + classificationsToInclude: '' + packageNameMasksToExclude: '' + packageNameMasksToInclude: '' + } + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + kbNumbersToExclude: '' + kbNumbersToInclude: '' + } +} +param location = '' +param maintenanceScope = 'InGuestPatch' +param maintenanceWindow = { + duration: '03:00' + expirationDateTime: '9999-12-31 23:59:59' + recurEvery: 'Day' + startDateTime: '2022-12-31 13:00' + timeZone: 'W. Europe Standard Time' +} +param namespace = 'mmcwafns' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = 'Custom' +``` + +
    +

    + ## Parameters **Required parameters** @@ -528,6 +667,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Scheduled Patching Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/managed-identity/user-assigned-identity/README.md b/avm/res/managed-identity/user-assigned-identity/README.md index 6ab0ca2082..c84308a3fc 100644 --- a/avm/res/managed-identity/user-assigned-identity/README.md +++ b/avm/res/managed-identity/user-assigned-identity/README.md @@ -57,7 +57,7 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

    -via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-identity/user-assigned-identity:' + +// Required parameters +param name = 'miuaimin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -151,7 +167,7 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

    -via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +243,68 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-identity/user-assigned-identity:' + +// Required parameters +param name = 'miuaimax001' +// Non-required parameters +param federatedIdentityCredentials = [ + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaimax-001' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaimax-002' + subject: 'system:serviceaccount:default:workload-identity-sa' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'b1a2c427-c4b1-435a-9b82-40c1b59537ac' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -280,7 +358,7 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

    -via JSON Parameter file +via JSON parameters file ```json { @@ -335,6 +413,49 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-identity/user-assigned-identity:' + +// Required parameters +param name = 'miuaiwaf001' +// Non-required parameters +param federatedIdentityCredentials = [ + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaiwaf-001' + subject: 'system:serviceaccount:default:workload-identity-sa' + } + { + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: '' + name: 'test-fed-cred-miuaiwaf-002' + subject: 'system:serviceaccount:default:workload-identity-sa' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -463,6 +584,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Managed Identity Contributor'` + - `'Managed Identity Operator'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/managed-services/registration-definition/README.md b/avm/res/managed-services/registration-definition/README.md index 85cea5188b..98aa0aafa7 100644 --- a/avm/res/managed-services/registration-definition/README.md +++ b/avm/res/managed-services/registration-definition/README.md @@ -75,7 +75,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    -via JSON Parameter file +via JSON parameters file ```json { @@ -115,6 +115,34 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdmin Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -163,7 +191,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    -via JSON Parameter file +via JSON parameters file ```json { @@ -215,6 +243,44 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + principalIdDisplayName: 'Lighthouse Contributor' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + principalIdDisplayName: 'Managed Services Registration assignment Delete Role' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } + { + delegatedRoleDefinitionIds: [ + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ] + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdmax Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +param registrationId = '' +``` + +
    +

    + ### Example 3: _Resource group deployment_ This instance deploys the module on a resource group. @@ -255,7 +321,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    -via JSON Parameter file +via JSON parameters file ```json { @@ -301,6 +367,36 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdrg Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +param registrationId = '' +param resourceGroupName = '' +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -340,7 +436,7 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    -via JSON Parameter file +via JSON parameters file ```json { @@ -383,6 +479,35 @@ module registrationDefinition 'br/public:avm/res/managed-services/registration-d

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/managed-services/registration-definition:' + +// Required parameters +param authorizations = [ + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: 'ecadddf6-78c3-4516-afb2-7d30a174ea13' + roleDefinitionId: '91c1777a-f3dc-4fae-b103-61d183457e46' + } +] +param managedByTenantId = '' +param name = 'Component Validation - msrdwaf Subscription assignment' +param registrationDescription = 'Managed by Lighthouse' +// Non-required parameters +param metadataLocation = '' +param resourceGroupName = '' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/management/management-group/README.md b/avm/res/management/management-group/README.md index 774c011294..ebd306ab99 100644 --- a/avm/res/management/management-group/README.md +++ b/avm/res/management/management-group/README.md @@ -59,7 +59,7 @@ module managementGroup 'br/public:avm/res/management/management-group:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,22 @@ module managementGroup 'br/public:avm/res/management/management-group:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/management/management-group:' + +// Required parameters +param name = 'mmgmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -109,7 +125,7 @@ module managementGroup 'br/public:avm/res/management/management-group:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -137,6 +153,24 @@ module managementGroup 'br/public:avm/res/management/management-group:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/management/management-group:' + +// Required parameters +param name = 'mmgmax001' +// Non-required parameters +param displayName = 'Test MG' +param location = '' +param parentId = '' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -165,7 +199,7 @@ module managementGroup 'br/public:avm/res/management/management-group:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -193,6 +227,24 @@ module managementGroup 'br/public:avm/res/management/management-group:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/management/management-group:' + +// Required parameters +param name = 'mmgwaf001' +// Non-required parameters +param displayName = 'Test MG' +param location = '' +param parentId = '' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/net-app/net-app-account/README.md b/avm/res/net-app/net-app-account/README.md index 7ee4003cbe..3a41e6dc96 100644 --- a/avm/res/net-app/net-app-account/README.md +++ b/avm/res/net-app/net-app-account/README.md @@ -63,7 +63,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -85,6 +85,22 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -226,7 +242,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -371,6 +387,137 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaamax001' +// Non-required parameters +param capacityPools = [ + { + name: 'nanaamax-cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + encryptionKeySource: '' + exportPolicyRules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + name: 'nanaamax-vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + '1' + ] + } + { + encryptionKeySource: '' + exportPolicyRules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: false + nfsv41: true + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + name: 'nanaamax-vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv4.1' + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + '1' + ] + } + ] + } + { + name: 'nanaamax-cp-002' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param roleAssignments = [ + { + name: '18051111-2a33-4f8e-8b24-441aac1e6562' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using nfs31 parameter set_ This instance deploys the module with nfs31. @@ -499,7 +646,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -631,6 +778,124 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaanfs3001' +// Non-required parameters +param capacityPools = [ + { + name: 'nanaanfs3-cp-001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [ + { + encryptionKeySource: '' + exportPolicyRules: [ + { + allowedClients: '0.0.0.0/0' + nfsv3: true + nfsv41: false + ruleIndex: 1 + unixReadOnly: false + unixReadWrite: true + } + ] + name: 'nanaanfs3-vol-001' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv3' + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + '1' + ] + } + { + encryptionKeySource: '' + name: 'nanaanfs3-vol-002' + networkFeatures: 'Standard' + protocolTypes: [ + 'NFSv3' + ] + subnetResourceId: '' + usageThreshold: 107374182400 + zones: [ + '1' + ] + } + ] + } + { + name: 'nanaanfs3-cp-002' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + serviceLevel: 'Premium' + size: 4398046511104 + volumes: [] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Contact: 'test.user@testcompany.com' + CostCenter: '7890' + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + PurchaseOrder: '1234' + Role: 'DeploymentValidation' + ServiceName: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -660,7 +925,7 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -687,6 +952,25 @@ module netAppAccount 'br/public:avm/res/net-app/net-app-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/net-app/net-app-account:' + +// Required parameters +param name = 'nanaawaf001' +// Non-required parameters +param location = '' +param tags = { + service: 'netapp' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -951,6 +1235,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/net-app/net-app-account/capacity-pool/README.md b/avm/res/net-app/net-app-account/capacity-pool/README.md index e8d582aa36..4c95a9ca0b 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/README.md @@ -130,6 +130,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md index f7d5472e35..9361b0045e 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md @@ -399,6 +399,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/application-gateway-web-application-firewall-policy/README.md b/avm/res/network/application-gateway-web-application-firewall-policy/README.md index 19c7a54ed5..d66c625612 100644 --- a/avm/res/network/application-gateway-web-application-firewall-policy/README.md +++ b/avm/res/network/application-gateway-web-application-firewall-policy/README.md @@ -62,7 +62,7 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

    -via JSON Parameter file +via JSON parameters file ```json { @@ -94,6 +94,30 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' + +// Required parameters +param managedRules = { + managedRuleSets: [ + { + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + ] +} +param name = 'nagwafpmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -144,7 +168,7 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

    -via JSON Parameter file +via JSON parameters file ```json { @@ -196,6 +220,46 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' + +// Required parameters +param managedRules = { + managedRuleSets: [ + { + ruleGroupOverrides: [] + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + { + ruleGroupOverrides: [] + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] +} +param name = 'nagwafpmax001' +// Non-required parameters +param location = '' +param policySettings = { + fileUploadLimitInMb: 10 + mode: 'Prevention' + state: 'Enabled' +} +param tags = { + 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. @@ -245,7 +309,7 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

    -via JSON Parameter file +via JSON parameters file ```json { @@ -296,6 +360,45 @@ module applicationGatewayWebApplicationFirewallPolicy 'br/public:avm/res/network

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway-web-application-firewall-policy:' + +// Required parameters +param managedRules = { + managedRuleSets: [ + { + ruleGroupOverrides: [] + ruleSetType: 'OWASP' + ruleSetVersion: '3.2' + } + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '0.1' + } + ] +} +param name = 'nagwafpwaf001' +// Non-required parameters +param location = '' +param policySettings = { + fileUploadLimitInMb: 10 + mode: 'Prevention' + state: 'Enabled' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/network/application-gateway/README.md b/avm/res/network/application-gateway/README.md index b5d206d002..fb363e99f3 100644 --- a/avm/res/network/application-gateway/README.md +++ b/avm/res/network/application-gateway/README.md @@ -136,7 +136,7 @@ module applicationGateway 'br/public:avm/res/network/application-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -248,6 +248,98 @@ module applicationGateway 'br/public:avm/res/network/application-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway:' + +// Required parameters +param name = '' +// Non-required parameters +param backendAddressPools = [ + { + name: 'backendAddressPool1' + } +] +param backendHttpSettingsCollection = [ + { + name: 'backendHttpSettings1' + properties: { + cookieBasedAffinity: 'Disabled' + port: 80 + protocol: 'Http' + } + } +] +param frontendIPConfigurations = [ + { + name: 'frontendIPConfig1' + properties: { + publicIPAddress: { + id: '' + } + } + } +] +param frontendPorts = [ + { + name: 'frontendPort1' + properties: { + port: 80 + } + } +] +param gatewayIPConfigurations = [ + { + name: 'publicIPConfig1' + properties: { + subnet: { + id: '' + } + } + } +] +param httpListeners = [ + { + name: 'httpListener1' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostName: 'www.contoso.com' + protocol: 'Http' + } + } +] +param location = '' +param requestRoutingRules = [ + { + name: 'requestRoutingRule1' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 100 + ruleType: 'Basic' + } + } +] +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -718,7 +810,7 @@ module applicationGateway 'br/public:avm/res/network/application-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -1230,6 +1322,466 @@ module applicationGateway 'br/public:avm/res/network/application-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway:' + +// Required parameters +param name = '' +// Non-required parameters +param backendAddressPools = [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } +] +param backendHttpSettingsCollection = [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '' + } + protocol: 'Http' + requestTimeout: 30 + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +enableHttp2: true +param enableTelemetry = '' +param frontendIPConfigurations = [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: '' + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateLinkConfiguration: { + id: '' + } + publicIPAddress: { + id: '' + } + } + } +] +param frontendPorts = [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } +] +param gatewayIPConfigurations = [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: '' + } + } + } +] +param httpListeners = [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'public' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param privateLinkConfigurations = [ + { + id: '' + name: 'pvtlink01' + properties: { + ipConfigurations: [ + { + id: '' + name: 'privateLinkIpConfig1' + properties: { + primary: false + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + } + } +] +param probes = [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } +] +param redirectConfigurations = [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } +] +param requestRoutingRules = [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '' + } + priority: 300 + redirectConfiguration: { + id: '' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '' + } + priority: 350 + redirectConfiguration: { + id: '' + } + rewriteRuleSet: { + id: '' + } + ruleType: 'Basic' + } + } +] +param rewriteRuleSets = [ + { + id: '' + name: 'customRewrite' + properties: { + rewriteRules: [ + { + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + conditions: [] + name: 'NewRewrite' + ruleSequence: 100 + } + ] + } + } +] +param roleAssignments = [ + { + name: '97fc1da9-bfe4-409d-b17a-da9a82fad0d0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'WAF_v2' +param sslCertificates = [ + { + name: 'az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: '' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param webApplicationFirewallConfiguration = { + disabledRuleGroups: [ + { + ruleGroupName: 'Known-CVEs' + } + { + ruleGroupName: 'REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION' + } + { + ruleGroupName: 'REQUEST-941-APPLICATION-ATTACK-XSS' + } + ] + enabled: true + exclusions: [ + { + matchVariable: 'RequestHeaderNames' + selector: 'hola' + selectorMatchOperator: 'StartsWith' + } + ] + fileUploadLimitInMb: 100 + firewallMode: 'Detection' + maxRequestBodySizeInKb: 128 + requestBodyCheck: true + ruleSetType: 'OWASP' + ruleSetVersion: '3.0' +} +param zones = [ + '1' + '2' + '3' +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1650,7 +2202,7 @@ module applicationGateway 'br/public:avm/res/network/application-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -2108,6 +2660,416 @@ module applicationGateway 'br/public:avm/res/network/application-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-gateway:' + +// Required parameters +param name = '' +// Non-required parameters +param backendAddressPools = [ + { + name: 'appServiceBackendPool' + properties: { + backendAddresses: [ + { + fqdn: 'aghapp.azurewebsites.net' + } + ] + } + } + { + name: 'privateVmBackendPool' + properties: { + backendAddresses: [ + { + ipAddress: '10.0.0.4' + } + ] + } + } +] +param backendHttpSettingsCollection = [ + { + name: 'appServiceBackendHttpsSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: true + port: 443 + protocol: 'Https' + requestTimeout: 30 + } + } + { + name: 'privateVmHttpSetting' + properties: { + cookieBasedAffinity: 'Disabled' + pickHostNameFromBackendAddress: false + port: 80 + probe: { + id: '' + } + protocol: 'Http' + requestTimeout: 30 + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +enableHttp2: true +param enableTelemetry = '' +param firewallPolicyResourceId = '' +param frontendIPConfigurations = [ + { + name: 'private' + properties: { + privateIPAddress: '10.0.0.20' + privateIPAllocationMethod: 'Static' + subnet: { + id: '' + } + } + } + { + name: 'public' + properties: { + privateIPAllocationMethod: 'Dynamic' + privateLinkConfiguration: { + id: '' + } + publicIPAddress: { + id: '' + } + } + } +] +param frontendPorts = [ + { + name: 'port443' + properties: { + port: 443 + } + } + { + name: 'port4433' + properties: { + port: 4433 + } + } + { + name: 'port80' + properties: { + port: 80 + } + } + { + name: 'port8080' + properties: { + port: 8080 + } + } +] +param gatewayIPConfigurations = [ + { + name: 'apw-ip-configuration' + properties: { + subnet: { + id: '' + } + } + } +] +param httpListeners = [ + { + name: 'public443' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'private4433' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'https' + requireServerNameIndication: false + sslCertificate: { + id: '' + } + } + } + { + name: 'httpRedirect80' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } + { + name: 'httpRedirect8080' + properties: { + frontendIPConfiguration: { + id: '' + } + frontendPort: { + id: '' + } + hostNames: [] + protocol: 'Http' + requireServerNameIndication: false + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'public' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +] +param privateLinkConfigurations = [ + { + id: '' + name: 'pvtlink01' + properties: { + ipConfigurations: [ + { + id: '' + name: 'privateLinkIpConfig1' + properties: { + primary: false + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } + ] + } + } +] +param probes = [ + { + name: 'privateVmHttpSettingProbe' + properties: { + host: '10.0.0.4' + interval: 60 + match: { + statusCodes: [ + '200' + '401' + ] + } + minServers: 3 + path: '/' + pickHostNameFromBackendHttpSettings: false + protocol: 'Http' + timeout: 15 + unhealthyThreshold: 5 + } + } +] +param redirectConfigurations = [ + { + name: 'httpRedirect80' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } + { + name: 'httpRedirect8080' + properties: { + includePath: true + includeQueryString: true + redirectType: 'Permanent' + requestRoutingRules: [ + { + id: '' + } + ] + targetListener: { + id: '' + } + } + } +] +param requestRoutingRules = [ + { + name: 'public443-appServiceBackendHttpsSetting-appServiceBackendHttpsSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 200 + ruleType: 'Basic' + } + } + { + name: 'private4433-privateVmHttpSetting-privateVmHttpSetting' + properties: { + backendAddressPool: { + id: '' + } + backendHttpSettings: { + id: '' + } + httpListener: { + id: '' + } + priority: 250 + ruleType: 'Basic' + } + } + { + name: 'httpRedirect80-public443' + properties: { + httpListener: { + id: '' + } + priority: 300 + redirectConfiguration: { + id: '' + } + ruleType: 'Basic' + } + } + { + name: 'httpRedirect8080-private4433' + properties: { + httpListener: { + id: '' + } + priority: 350 + redirectConfiguration: { + id: '' + } + rewriteRuleSet: { + id: '' + } + ruleType: 'Basic' + } + } +] +param rewriteRuleSets = [ + { + id: '' + name: 'customRewrite' + properties: { + rewriteRules: [ + { + actionSet: { + requestHeaderConfigurations: [ + { + headerName: 'Content-Type' + headerValue: 'JSON' + } + { + headerName: 'someheader' + } + ] + responseHeaderConfigurations: [] + } + conditions: [] + name: 'NewRewrite' + ruleSequence: 100 + } + ] + } + } +] +param sku = 'WAF_v2' +param sslCertificates = [ + { + name: 'az-apgw-x-001-ssl-certificate' + properties: { + keyVaultSecretId: '' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2840,6 +3802,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2984,6 +3957,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/application-security-group/README.md b/avm/res/network/application-security-group/README.md index 227c71bc93..7ef8c039c8 100644 --- a/avm/res/network/application-security-group/README.md +++ b/avm/res/network/application-security-group/README.md @@ -56,7 +56,7 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-security-group:' + +// Required parameters +param name = 'nasgmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -132,7 +148,7 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

    -via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-security-group:' + +// Required parameters +param name = 'nasgmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'e9e73878-302e-4e67-a2f8-981ea073bdf7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -223,7 +283,7 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

    -via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +318,31 @@ module applicationSecurityGroup 'br/public:avm/res/network/application-security-

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/application-security-group:' + +// Required parameters +param name = 'nasgwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -341,6 +426,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index cb38f1c505..5d8d346c88 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -83,7 +83,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -131,6 +131,40 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafaddpip001' +// Non-required parameters +param additionalPublicIpConfigurations = [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } +] +param azureSkuTier = 'Basic' +param location = '' +param managementIPAddressObject = { + publicIPAllocationMethod: 'Static' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] +} +param virtualNetworkResourceId = '' +``` + +
    +

    + ### Example 2: _Basic SKU_ This instance deploys the module with the Basic SKU. @@ -161,7 +195,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -195,6 +229,26 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafbasic001' +// Non-required parameters +param azureSkuTier = 'Basic' +param location = '' +param networkRuleCollections = [] +param threatIntelMode = 'Deny' +param virtualNetworkResourceId = '' +``` + +
    +

    + ### Example 3: _Custom-PIP_ This instance deploys the module and will create a public IP address. @@ -250,7 +304,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -305,6 +359,51 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafcstpip001' +// Non-required parameters +param location = '' +param publicIPAddressObject = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'new-pip-nafcstpip' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + skuName: 'Standard' + skuTier: 'Regional' +} +param virtualNetworkResourceId = '' +``` + +
    +

    + ### Example 4: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -332,7 +431,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -357,6 +456,23 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafmin001' +// Non-required parameters +param location = '' +param virtualNetworkResourceId = '' +``` + +
    +

    + ### Example 5: _Hub-commom_ This instance deploys the module a vWAN in a typical hub setting. @@ -390,7 +506,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -425,6 +541,29 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafhubcom001' +// Non-required parameters +param firewallPolicyId = '' +param hubIPAddresses = { + publicIPs: { + count: 1 + } +} +param location = '' +param virtualHubId = '' +``` + +
    +

    + ### Example 6: _Hub-min_ This instance deploys the module a vWAN minimum hub setting. @@ -457,7 +596,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -489,6 +628,28 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafhubmin001' +// Non-required parameters +param hubIPAddresses = { + publicIPs: { + count: 1 + } +} +param location = '' +param virtualHubId = '' +``` + +
    +

    + ### Example 7: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -661,7 +822,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -847,6 +1008,168 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafmax001' +// Non-required parameters +param applicationRuleCollections = [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkRuleCollections = [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + { + description: 'allow azure devops' + destinationAddresses: [ + 'AzureDevOps' + ] + destinationPorts: [ + '443' + ] + name: 'allow-azure-devops' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } +] +param publicIPResourceID = '' +param roleAssignments = [ + { + name: '3a8da184-d6d8-4bea-b992-e27cc053ef21' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkResourceId = '' +param zones = [ + '1' + '2' + '3' +] +``` + +
    +

    + ### Example 8: _Public-IP-Prefix_ This instance deploys the module and will use a public IP prefix. @@ -890,7 +1213,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -939,6 +1262,39 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafpip001' +// Non-required parameters +param azureSkuTier = 'Basic' +param location = '' +param managementIPAddressObject = { + managementIPAllocationMethod: 'Static' + managementIPPrefixResourceId: '' + name: 'managementIP01' + skuName: 'Standard' + skuTier: 'Regional' +} +param publicIPAddressObject = { + name: 'publicIP01' + publicIPAllocationMethod: 'Static' + publicIPPrefixResourceId: '' + skuName: 'Standard' + skuTier: 'Regional' +} +param virtualNetworkResourceId = '' +param zones = [] +``` + +
    +

    + ### Example 9: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1072,7 +1428,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1215,6 +1571,129 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'nafwaf001' +// Non-required parameters +param applicationRuleCollections = [ + { + name: 'allow-app-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + fqdnTags: [ + 'AppServiceEnvironment' + 'WindowsUpdate' + ] + name: 'allow-ase-tags' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + } + { + name: 'allow-ase-management' + protocols: [ + { + port: 80 + protocolType: 'Http' + } + { + port: 443 + protocolType: 'Https' + } + ] + sourceAddresses: [ + '*' + ] + targetFqdns: [ + 'bing.com' + ] + } + ] + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param networkRuleCollections = [ + { + name: 'allow-network-rules' + properties: { + action: { + type: 'Allow' + } + priority: 100 + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '12000' + '123' + ] + name: 'allow-ntp' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } + ] + } + } +] +param publicIPResourceID = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkResourceId = '' +param zones = [ + '1' + '2' + '3' +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -2079,6 +2558,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/bastion-host/README.md b/avm/res/network/bastion-host/README.md index a7c2f5dd91..8c95b14dac 100644 --- a/avm/res/network/bastion-host/README.md +++ b/avm/res/network/bastion-host/README.md @@ -99,7 +99,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -164,6 +164,61 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhctmpip001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +param publicIPAddressObject = { + allocationMethod: 'Static' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nbhctmpip001-pip' + publicIPPrefixResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + skuName: 'Standard' + skuTier: 'Regional' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] +} +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -191,7 +246,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -216,6 +271,23 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhmin001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -287,7 +359,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -378,6 +450,67 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhmax001' +param virtualNetworkResourceId = '' +// Non-required parameters +param bastionSubnetPublicIpResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableCopyPaste = true +param enableFileCopy = false +param enableIpConnect = false +param enableShareableLink = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'a9329bd8-d7c8-4915-9dfe-04197fa5bf45' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scaleUnits = 4 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -426,7 +559,7 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -490,6 +623,44 @@ module bastionHost 'br/public:avm/res/network/bastion-host:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/bastion-host:' + +// Required parameters +param name = 'nbhwaf001' +param virtualNetworkResourceId = '' +// Non-required parameters +param bastionSubnetPublicIpResourceId = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableCopyPaste = true +param enableFileCopy = false +param enableIpConnect = false +param enableShareableLink = false +param location = '' +param scaleUnits = 4 +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -764,6 +935,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/connection/README.md b/avm/res/network/connection/README.md index 1daee9d401..5bf3869260 100644 --- a/avm/res/network/connection/README.md +++ b/avm/res/network/connection/README.md @@ -64,7 +64,7 @@ module connection 'br/public:avm/res/network/connection:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -102,6 +102,30 @@ module connection 'br/public:avm/res/network/connection:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/connection:' + +// Required parameters +param name = 'ncmin001' +virtualNetworkGateway1: { + id: '' +} +// Non-required parameters +param connectionType = 'Vnet2Vnet' +param location = '' +virtualNetworkGateway2: { + id: '' +} +param vpnSharedKey = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -148,7 +172,7 @@ module connection 'br/public:avm/res/network/connection:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -208,6 +232,42 @@ module connection 'br/public:avm/res/network/connection:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/connection:' + +// Required parameters +param name = 'ncmax001' +virtualNetworkGateway1: { + id: '' +} +// Non-required parameters +param connectionType = 'Vnet2Vnet' +param dpdTimeoutSeconds = 45 +param enableBgp = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param usePolicyBasedTrafficSelectors = false +virtualNetworkGateway2: { + id: '' +} +param vpnSharedKey = '' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -251,7 +311,7 @@ module connection 'br/public:avm/res/network/connection:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -302,6 +362,39 @@ module connection 'br/public:avm/res/network/connection:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/connection:' + +// Required parameters +param name = 'ncwaf001' +virtualNetworkGateway1: { + id: '' +} +// Non-required parameters +param connectionType = 'Vnet2Vnet' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +virtualNetworkGateway2: { + id: '' +} +param vpnSharedKey = '' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/network/ddos-protection-plan/README.md b/avm/res/network/ddos-protection-plan/README.md index 5d9187c4d3..6465acbe17 100644 --- a/avm/res/network/ddos-protection-plan/README.md +++ b/avm/res/network/ddos-protection-plan/README.md @@ -56,7 +56,7 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ddos-protection-plan:' + +// Required parameters +param name = 'ndppmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -132,7 +148,7 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ddos-protection-plan:' + +// Required parameters +param name = 'ndppmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '60339368-138d-4667-988a-5431c156f6ff' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -223,7 +283,7 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +318,31 @@ module ddosProtectionPlan 'br/public:avm/res/network/ddos-protection-plan:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ddos-protection-plan:' + +// Required parameters +param name = 'ndppwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -341,6 +426,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-forwarding-ruleset/README.md b/avm/res/network/dns-forwarding-ruleset/README.md index d126a5c2a5..8e1cb79b7d 100644 --- a/avm/res/network/dns-forwarding-ruleset/README.md +++ b/avm/res/network/dns-forwarding-ruleset/README.md @@ -61,7 +61,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,25 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-forwarding-ruleset:' + +// Required parameters +param dnsForwardingRulesetOutboundEndpointResourceIds = [ + '' +] +param name = 'ndfrsmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -115,7 +134,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -190,7 +209,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-forwarding-ruleset:' + +// Required parameters +param dnsForwardingRulesetOutboundEndpointResourceIds = [ + '' +] +param name = 'ndfrsmax001' +// Non-required parameters +param forwardingRules = [ + { + domainName: 'contoso.' + forwardingRuleState: 'Enabled' + name: 'rule1' + targetDnsServers: [ + { + ipAddress: '192.168.0.1' + port: 53 + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '38837eb6-838b-4c77-8d7d-baa102195d9f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkLinks = [ + { + name: 'mytestvnetlink1' + virtualNetworkResourceId: '' + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -286,7 +371,7 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -326,6 +411,34 @@ module dnsForwardingRuleset 'br/public:avm/res/network/dns-forwarding-ruleset:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-forwarding-ruleset:' + +// Required parameters +param dnsForwardingRulesetOutboundEndpointResourceIds = [ + '' +] +param name = 'ndfrswaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -417,7 +530,7 @@ The target DNS servers to forward to. | Parameter | Type | Description | | :-- | :-- | :-- | | [`ipAddress`](#parameter-forwardingrulestargetdnsserversipaddress) | string | The IP address of the target DNS server. | -| [`port`](#parameter-forwardingrulestargetdnsserversport) | string | The port of the target DNS server. | +| [`port`](#parameter-forwardingrulestargetdnsserversport) | int | The port of the target DNS server. | ### Parameter: `forwardingRules.targetDnsServers.ipAddress` @@ -431,7 +544,7 @@ The IP address of the target DNS server. The port of the target DNS server. - Required: Yes -- Type: string +- Type: int ### Parameter: `forwardingRules.forwardingRuleState` @@ -504,6 +617,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/dns-forwarding-ruleset/forwarding-rule/main.json b/avm/res/network/dns-forwarding-ruleset/forwarding-rule/main.json index 7946899042..f592f4e4ec 100644 --- a/avm/res/network/dns-forwarding-ruleset/forwarding-rule/main.json +++ b/avm/res/network/dns-forwarding-ruleset/forwarding-rule/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17239011184377594139" + "version": "0.30.23.60470", + "templateHash": "10407418001531703281" }, "name": "Dns Forwarding Rulesets Forwarding Rules", "description": "This template deploys Forwarding Rule in a Dns Forwarding Ruleset.", diff --git a/avm/res/network/dns-forwarding-ruleset/main.bicep b/avm/res/network/dns-forwarding-ruleset/main.bicep index b811a1ff3f..7283304df1 100644 --- a/avm/res/network/dns-forwarding-ruleset/main.bicep +++ b/avm/res/network/dns-forwarding-ruleset/main.bicep @@ -235,5 +235,5 @@ type targetDnsServers = { ipAddress: string @description('Required. The port of the target DNS server.') - port: string + port: int }[] diff --git a/avm/res/network/dns-forwarding-ruleset/main.json b/avm/res/network/dns-forwarding-ruleset/main.json index 2524162174..6d4f098492 100644 --- a/avm/res/network/dns-forwarding-ruleset/main.json +++ b/avm/res/network/dns-forwarding-ruleset/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8260746772295919880" + "version": "0.30.23.60470", + "templateHash": "4145709731033849736" }, "name": "Dns Forwarding Rulesets", "description": "This template deploys an dns forwarding ruleset.", @@ -190,7 +190,7 @@ } }, "port": { - "type": "string", + "type": "int", "metadata": { "description": "Required. The port of the target DNS server." } @@ -394,8 +394,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17239011184377594139" + "version": "0.30.23.60470", + "templateHash": "10407418001531703281" }, "name": "Dns Forwarding Rulesets Forwarding Rules", "description": "This template deploys Forwarding Rule in a Dns Forwarding Ruleset.", @@ -522,8 +522,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14775682641579876025" + "version": "0.30.23.60470", + "templateHash": "7319659019579418232" }, "name": "Dns Forwarding Rulesets Virtual Network Links", "description": "This template deploys Virtual Network Link in a Dns Forwarding Ruleset.", diff --git a/avm/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep b/avm/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep index 8a956dbc16..f8f66cd66c 100644 --- a/avm/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep +++ b/avm/res/network/dns-forwarding-ruleset/tests/e2e/max/main.test.bicep @@ -71,7 +71,7 @@ module testDeployment '../../../main.bicep' = [ targetDnsServers: [ { ipAddress: '192.168.0.1' - port: '53' + port: 53 } ] } diff --git a/avm/res/network/dns-forwarding-ruleset/version.json b/avm/res/network/dns-forwarding-ruleset/version.json index 13669e6601..ea4f3b6e67 100644 --- a/avm/res/network/dns-forwarding-ruleset/version.json +++ b/avm/res/network/dns-forwarding-ruleset/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.4", + "version": "0.5", "pathFilters": [ "./main.json" ] diff --git a/avm/res/network/dns-forwarding-ruleset/virtual-network-link/main.json b/avm/res/network/dns-forwarding-ruleset/virtual-network-link/main.json index 3f0af9c907..8cdbb65fc7 100644 --- a/avm/res/network/dns-forwarding-ruleset/virtual-network-link/main.json +++ b/avm/res/network/dns-forwarding-ruleset/virtual-network-link/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "14775682641579876025" + "version": "0.30.23.60470", + "templateHash": "7319659019579418232" }, "name": "Dns Forwarding Rulesets Virtual Network Links", "description": "This template deploys Virtual Network Link in a Dns Forwarding Ruleset.", diff --git a/avm/res/network/dns-resolver/README.md b/avm/res/network/dns-resolver/README.md index 8437207f1f..83f5b9b167 100644 --- a/avm/res/network/dns-resolver/README.md +++ b/avm/res/network/dns-resolver/README.md @@ -59,7 +59,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-resolver:' + +// Required parameters +param name = 'ndrmin001' +param virtualNetworkResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -151,7 +168,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -226,6 +243,63 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-resolver:' + +// Required parameters +param name = 'ndrmax001' +param virtualNetworkResourceId = '' +// Non-required parameters +param inboundEndpoints = [ + { + name: 'ndrmax-az-pdnsin-x-001' + subnetResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundEndpoints = [ + { + name: 'ndrmax-az-pdnsout-x-001' + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '83c82ade-1ada-4374-82d0-325f39a44af6' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -274,7 +348,7 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -328,6 +402,44 @@ module dnsResolver 'br/public:avm/res/network/dns-resolver:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-resolver:' + +// Required parameters +param name = 'ndrwaf001' +param virtualNetworkResourceId = '' +// Non-required parameters +param inboundEndpoints = [ + { + name: 'ndrwaf-az-pdnsin-x-001' + subnetResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundEndpoints = [ + { + name: 'ndrwaf-az-pdnsout-x-001' + subnetResourceId: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -542,6 +654,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/README.md b/avm/res/network/dns-zone/README.md index 8a4e661ec1..2d49c7a920 100644 --- a/avm/res/network/dns-zone/README.md +++ b/avm/res/network/dns-zone/README.md @@ -66,7 +66,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,22 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-zone:' + +// Required parameters +param name = 'ndzmin001.com' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -419,7 +435,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -772,6 +788,327 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-zone:' + +// Required parameters +param name = 'ndzmax001.com' +// Non-required parameters +param a = [ + { + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + name: 'A_10.240.4.4' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param aaaa = [ + { + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + } +] +param caa = [ + { + caaRecords: [ + { + flags: 0 + tag: 'issue' + value: 'ca.contoso.com' + } + ] + name: 'CAA_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param cname = [ + { + cnameRecord: { + cname: 'test' + } + name: 'CNAME_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } + { + name: 'CNAME_aliasRecordSet' + targetResourceId: '' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param mx = [ + { + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + name: 'MX_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param ns = [ + { + name: 'NS_test' + nsRecords: [ + { + nsdname: 'ns.contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param ptr = [ + { + name: 'PTR_contoso' + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param roleAssignments = [ + { + name: 'a8697438-70e8-4f40-baa4-6e90a57fe1dc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param soa = [ + { + name: '@' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soaRecord: { + email: 'azuredns-hostmaster.microsoft.com' + expireTime: 2419200 + host: 'ns1-04.azure-dns.com.' + minimumTtl: 300 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + ttl: 3600 + } +] +param srv = [ + { + name: 'SRV_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + ttl: 3600 + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param txt = [ + { + name: 'TXT_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -807,7 +1144,7 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -842,6 +1179,31 @@ module dnsZone 'br/public:avm/res/network/dns-zone:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/dns-zone:' + +// Required parameters +param name = 'ndzwaf001.com' +// Non-required parameters +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -940,6 +1302,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1108,6 +1482,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1291,6 +1677,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1452,6 +1850,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1679,6 +2089,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1839,6 +2261,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1999,6 +2433,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2103,6 +2549,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2236,6 +2694,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2444,6 +2914,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2635,6 +3117,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/a/README.md b/avm/res/network/dns-zone/a/README.md index 8d42ef0747..e93a99ac4a 100644 --- a/avm/res/network/dns-zone/a/README.md +++ b/avm/res/network/dns-zone/a/README.md @@ -73,6 +73,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/aaaa/README.md b/avm/res/network/dns-zone/aaaa/README.md index 93755b92fc..99120461e1 100644 --- a/avm/res/network/dns-zone/aaaa/README.md +++ b/avm/res/network/dns-zone/aaaa/README.md @@ -73,6 +73,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/caa/README.md b/avm/res/network/dns-zone/caa/README.md index 8b433084d9..7d1b1ef225 100644 --- a/avm/res/network/dns-zone/caa/README.md +++ b/avm/res/network/dns-zone/caa/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/cname/README.md b/avm/res/network/dns-zone/cname/README.md index 197a33a7fd..7107700e87 100644 --- a/avm/res/network/dns-zone/cname/README.md +++ b/avm/res/network/dns-zone/cname/README.md @@ -73,6 +73,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/mx/README.md b/avm/res/network/dns-zone/mx/README.md index 19577e558e..68615af23c 100644 --- a/avm/res/network/dns-zone/mx/README.md +++ b/avm/res/network/dns-zone/mx/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/ns/README.md b/avm/res/network/dns-zone/ns/README.md index bf63641c45..43fd817fe2 100644 --- a/avm/res/network/dns-zone/ns/README.md +++ b/avm/res/network/dns-zone/ns/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/ptr/README.md b/avm/res/network/dns-zone/ptr/README.md index d5fffa162b..2dda8e4f59 100644 --- a/avm/res/network/dns-zone/ptr/README.md +++ b/avm/res/network/dns-zone/ptr/README.md @@ -72,6 +72,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/soa/README.md b/avm/res/network/dns-zone/soa/README.md index 3c0227fea8..22832138fb 100644 --- a/avm/res/network/dns-zone/soa/README.md +++ b/avm/res/network/dns-zone/soa/README.md @@ -65,6 +65,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/srv/README.md b/avm/res/network/dns-zone/srv/README.md index 309a786101..c733d69571 100644 --- a/avm/res/network/dns-zone/srv/README.md +++ b/avm/res/network/dns-zone/srv/README.md @@ -65,6 +65,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/dns-zone/txt/README.md b/avm/res/network/dns-zone/txt/README.md index dbc21c21cd..35f4be5c49 100644 --- a/avm/res/network/dns-zone/txt/README.md +++ b/avm/res/network/dns-zone/txt/README.md @@ -65,6 +65,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/express-route-circuit/README.md b/avm/res/network/express-route-circuit/README.md index 578169e9ff..9f1ad4093b 100644 --- a/avm/res/network/express-route-circuit/README.md +++ b/avm/res/network/express-route-circuit/README.md @@ -60,7 +60,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -91,6 +91,25 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-circuit:' + +// Required parameters +param bandwidthInMbps = 50 +param name = 'nercmin001' +param peeringLocation = 'Amsterdam' +param serviceProviderName = 'Equinix' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -165,7 +184,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -255,6 +274,70 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-circuit:' + +// Required parameters +param bandwidthInMbps = 50 +param name = 'nercmax001' +param peeringLocation = 'Amsterdam' +param serviceProviderName = 'Equinix' +// Non-required parameters +param allowClassicOperations = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'd7aa3dfa-6ba6-4ed8-b561-2164fbb1327e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuFamily = 'MeteredData' +param skuTier = 'Standard' +param tags = { + 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. @@ -310,7 +393,7 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -379,6 +462,51 @@ module expressRouteCircuit 'br/public:avm/res/network/express-route-circuit:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-circuit:' + +// Required parameters +param bandwidthInMbps = 50 +param name = 'nercwaf001' +param peeringLocation = 'Amsterdam' +param serviceProviderName = 'Equinix' +// Non-required parameters +param allowClassicOperations = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param skuFamily = 'MeteredData' +param skuTier = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -717,6 +845,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/express-route-gateway/README.md b/avm/res/network/express-route-gateway/README.md index cba6d19ddf..27da9983b7 100644 --- a/avm/res/network/express-route-gateway/README.md +++ b/avm/res/network/express-route-gateway/README.md @@ -57,7 +57,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,23 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-gateway:' + +// Required parameters +param name = 'nergmin001' +param virtualHubId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -138,7 +155,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -202,6 +219,52 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-gateway:' + +// Required parameters +param name = 'nergmax001' +param virtualHubId = '' +// Non-required parameters +param autoScaleConfigurationBoundsMax = 3 +param autoScaleConfigurationBoundsMin = 2 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '78ad6c3f-7f77-4d26-9576-dbd947241ef0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + hello: 'world' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -239,7 +302,7 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -282,6 +345,33 @@ module expressRouteGateway 'br/public:avm/res/network/express-route-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/express-route-gateway:' + +// Required parameters +param name = 'nergwaf001' +param virtualHubId = '' +// Non-required parameters +param autoScaleConfigurationBoundsMax = 3 +param autoScaleConfigurationBoundsMin = 2 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + hello: 'world' + 'hidden-title': 'This is visible in the resource name' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -409,6 +499,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/firewall-policy/README.md b/avm/res/network/firewall-policy/README.md index f0db15c291..067f1a3fe5 100644 --- a/avm/res/network/firewall-policy/README.md +++ b/avm/res/network/firewall-policy/README.md @@ -55,7 +55,7 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -77,6 +77,22 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/firewall-policy:' + +// Required parameters +param name = 'nfpmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -155,7 +171,7 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -243,6 +259,74 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/firewall-policy:' + +// Required parameters +param name = 'nfpmax001' +// Non-required parameters +param allowSqlRedirect = true +param autoLearnPrivateRanges = 'Enabled' +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param mode = 'Alert' +param ruleCollectionGroups = [ + { + name: 'rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param tier = 'Premium' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -315,7 +399,7 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -393,6 +477,68 @@ module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/firewall-policy:' + +// Required parameters +param name = 'nfpwaf001' +// Non-required parameters +param allowSqlRedirect = true +param autoLearnPrivateRanges = 'Enabled' +param location = '' +param ruleCollectionGroups = [ + { + name: 'rule-001' + priority: 5000 + ruleCollections: [ + { + action: { + type: 'Allow' + } + name: 'collection002' + priority: 5555 + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + rules: [ + { + destinationAddresses: [ + '*' + ] + destinationFqdns: [] + destinationIpGroups: [] + destinationPorts: [ + '80' + ] + ipProtocols: [ + 'TCP' + 'UDP' + ] + name: 'rule002' + ruleType: 'NetworkRule' + sourceAddresses: [ + '*' + ] + sourceIpGroups: [] + } + ] + } + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param threatIntelMode = 'Deny' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/network/front-door-web-application-firewall-policy/README.md b/avm/res/network/front-door-web-application-firewall-policy/README.md index 02c147d79e..830c52b31e 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/README.md +++ b/avm/res/network/front-door-web-application-firewall-policy/README.md @@ -16,7 +16,7 @@ This module deploys a Front Door Web Application Firewall (WAF) Policy. | :-- | :-- | | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Network/FrontDoorWebApplicationFirewallPolicies` | [2022-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-05-01/FrontDoorWebApplicationFirewallPolicies) | +| `Microsoft.Network/FrontDoorWebApplicationFirewallPolicies` | [2024-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/FrontDoorWebApplicationFirewallPolicies) | ## Usage examples @@ -56,7 +56,7 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door-web-application-firewall-policy:' + +// Required parameters +param name = 'nagwafpmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -195,7 +211,7 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

    -via JSON Parameter file +via JSON parameters file ```json { @@ -322,6 +338,113 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door-web-application-firewall-policy:' + +// Required parameters +param name = 'nagwafpmax001' +// Non-required parameters +param customRules = { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'CH' + ] + matchVariable: 'RemoteAddr' + negateCondition: false + operator: 'GeoMatch' + selector: '' + transforms: [] + } + { + matchValue: [ + 'windows' + ] + matchVariable: 'RequestHeader' + negateCondition: false + operator: 'Contains' + selector: 'UserAgent' + transforms: [] + } + { + matchValue: [ + '?>' + '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedRules = { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] +} +param policySettings = { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 200 + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' +} +param roleAssignments = [ + { + name: 'bb049c96-2571-4a25-b760-444ab25d86ed' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Premium_AzureFrontDoor' +param tags = { + 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. @@ -416,7 +539,7 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

    -via JSON Parameter file +via JSON parameters file ```json { @@ -516,6 +639,90 @@ module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-do

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door-web-application-firewall-policy:' + +// Required parameters +param name = 'nagwafpwaf001' +// Non-required parameters +param customRules = { + rules: [ + { + action: 'Block' + enabledState: 'Enabled' + matchConditions: [ + { + matchValue: [ + 'CH' + ] + matchVariable: 'RemoteAddr' + negateCondition: false + operator: 'GeoMatch' + selector: '' + transforms: [] + } + { + matchValue: [ + 'windows' + ] + matchVariable: 'RequestHeader' + negateCondition: false + operator: 'Contains' + selector: 'UserAgent' + transforms: [] + } + { + matchValue: [ + '?>' + '' +param managedRules = { + managedRuleSets: [ + { + ruleSetType: 'Microsoft_BotManagerRuleSet' + ruleSetVersion: '1.0' + } + ] +} +param policySettings = { + customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==' + customBlockResponseStatusCode: 200 + mode: 'Prevention' + redirectUrl: 'http://www.bing.com' +} +param sku = 'Premium_AzureFrontDoor' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -576,6 +783,116 @@ The custom rules inside the policy. } ``` +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rules`](#parameter-customrulesrules) | array | List of rules. | + +### Parameter: `customRules.rules` + +List of rules. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-customrulesrulesaction) | string | Describes what action to be applied when rule matches. | +| [`enabledState`](#parameter-customrulesrulesenabledstate) | string | Describes if the custom rule is in enabled or disabled state. | +| [`matchConditions`](#parameter-customrulesrulesmatchconditions) | array | List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details. | +| [`name`](#parameter-customrulesrulesname) | string | Describes the name of the rule. | +| [`priority`](#parameter-customrulesrulespriority) | int | Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value. | +| [`ruleType`](#parameter-customrulesrulesruletype) | string | Describes type of rule. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`rateLimitDurationInMinutes`](#parameter-customrulesrulesratelimitdurationinminutes) | int | Time window for resetting the rate limit count. Default is 1 minute. | +| [`rateLimitThreshold`](#parameter-customrulesrulesratelimitthreshold) | int | Number of allowed requests per client within the time window. | + +### Parameter: `customRules.rules.action` + +Describes what action to be applied when rule matches. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Block' + 'Log' + 'Redirect' + ] + ``` + +### Parameter: `customRules.rules.enabledState` + +Describes if the custom rule is in enabled or disabled state. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `customRules.rules.matchConditions` + +List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details. + +- Required: Yes +- Type: array + +### Parameter: `customRules.rules.name` + +Describes the name of the rule. + +- Required: Yes +- Type: string + +### Parameter: `customRules.rules.priority` + +Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value. + +- Required: Yes +- Type: int + +### Parameter: `customRules.rules.ruleType` + +Describes type of rule. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'MatchRule' + 'RateLimitRule' + ] + ``` + +### Parameter: `customRules.rules.rateLimitDurationInMinutes` + +Time window for resetting the rate limit count. Default is 1 minute. + +- Required: No +- Type: int + +### Parameter: `customRules.rules.rateLimitThreshold` + +Number of allowed requests per client within the time window. + +- Required: No +- Type: int + ### Parameter: `enableTelemetry` Enable/Disable usage telemetry for module. @@ -655,6 +972,77 @@ Describes the managedRules structure. } ``` +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedRuleSets`](#parameter-managedrulesmanagedrulesets) | array | List of rule sets. | + +### Parameter: `managedRules.managedRuleSets` + +List of rule sets. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`ruleSetType`](#parameter-managedrulesmanagedrulesetsrulesettype) | string | Defines the rule set type to use. | +| [`ruleSetVersion`](#parameter-managedrulesmanagedrulesetsrulesetversion) | string | Defines the version of the rule set to use. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`exclusions`](#parameter-managedrulesmanagedrulesetsexclusions) | array | Describes the exclusions that are applied to all rules in the set. | +| [`ruleGroupOverrides`](#parameter-managedrulesmanagedrulesetsrulegroupoverrides) | array | Defines the rule group overrides to apply to the rule set. | +| [`ruleSetAction`](#parameter-managedrulesmanagedrulesetsrulesetaction) | string | Defines the rule set action. | + +### Parameter: `managedRules.managedRuleSets.ruleSetType` + +Defines the rule set type to use. + +- Required: Yes +- Type: string + +### Parameter: `managedRules.managedRuleSets.ruleSetVersion` + +Defines the version of the rule set to use. + +- Required: Yes +- Type: string + +### Parameter: `managedRules.managedRuleSets.exclusions` + +Describes the exclusions that are applied to all rules in the set. + +- Required: No +- Type: array + +### Parameter: `managedRules.managedRuleSets.ruleGroupOverrides` + +Defines the rule group overrides to apply to the rule set. + +- Required: No +- Type: array + +### Parameter: `managedRules.managedRuleSets.ruleSetAction` + +Defines the rule set action. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Block' + 'Log' + 'Redirect' + ] + ``` + ### Parameter: `policySettings` The PolicySettings for policy. @@ -675,6 +1063,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/front-door-web-application-firewall-policy/main.bicep b/avm/res/network/front-door-web-application-firewall-policy/main.bicep index 377833654b..9d6421a9b8 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/main.bicep +++ b/avm/res/network/front-door-web-application-firewall-policy/main.bicep @@ -24,7 +24,7 @@ param tags object? param enableTelemetry bool = true @description('Optional. Describes the managedRules structure.') -param managedRules object = { +param managedRules managedRulesType = { managedRuleSets: [ { ruleSetType: 'Microsoft_DefaultRuleSet' @@ -43,7 +43,7 @@ param managedRules object = { } @description('Optional. The custom rules inside the policy.') -param customRules object = { +param customRules customRulesType = { rules: [ { name: 'ApplyGeoFilter' @@ -119,7 +119,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource frontDoorWAFPolicy 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2022-05-01' = { +resource frontDoorWAFPolicy 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2024-02-01' = { name: name location: location sku: { @@ -213,3 +213,56 @@ type roleAssignmentType = { @description('Optional. The Resource Id of the delegated managed identity resource.') delegatedManagedIdentityResourceId: string? }[]? + +type managedRulesType = { + @description('Optional. List of rule sets.') + managedRuleSets: managedRuleSetsType +} + +type managedRuleSetsType = { + @description('Required. Defines the rule set type to use.') + ruleSetType: string + + @description('Required. Defines the version of the rule set to use.') + ruleSetVersion: string + + @description('Optional. Defines the rule group overrides to apply to the rule set.') + ruleGroupOverrides: array? + + @description('Optional. Describes the exclusions that are applied to all rules in the set.') + exclusions: array? + + @description('Optional. Defines the rule set action.') + ruleSetAction: 'Block' | 'Log' | 'Redirect' | null +}[]? + +type customRulesType = { + @description('Optional. List of rules.') + rules: customRulesRuleType +} + +type customRulesRuleType = { + @description('Required. Describes what action to be applied when rule matches.') + action: 'Allow' | 'Block' | 'Log' | 'Redirect' + + @description('Required. Describes if the custom rule is in enabled or disabled state.') + enabledState: 'Enabled' | 'Disabled' + + @description('Required. List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details.') + matchConditions: array + + @description('Required. Describes the name of the rule.') + name: string + + @description('Required. Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value.') + priority: int + + @description('Optional. Time window for resetting the rate limit count. Default is 1 minute.') + rateLimitDurationInMinutes: int? + + @description('Optional. Number of allowed requests per client within the time window.') + rateLimitThreshold: int? + + @description('Required. Describes type of rule.') + ruleType: 'MatchRule' | 'RateLimitRule' +}[]? diff --git a/avm/res/network/front-door-web-application-firewall-policy/main.json b/avm/res/network/front-door-web-application-firewall-policy/main.json index de8d1b031c..8048f5de23 100644 --- a/avm/res/network/front-door-web-application-firewall-policy/main.json +++ b/avm/res/network/front-door-web-application-firewall-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8148563999971279398" + "version": "0.30.23.60470", + "templateHash": "13657670923843039959" }, "name": "Front Door Web Application Firewall (WAF) Policies", "description": "This module deploys a Front Door Web Application Firewall (WAF) Policy.", @@ -110,6 +110,148 @@ } }, "nullable": true + }, + "managedRulesType": { + "type": "object", + "properties": { + "managedRuleSets": { + "$ref": "#/definitions/managedRuleSetsType", + "metadata": { + "description": "Optional. List of rule sets." + } + } + } + }, + "managedRuleSetsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "ruleSetType": { + "type": "string", + "metadata": { + "description": "Required. Defines the rule set type to use." + } + }, + "ruleSetVersion": { + "type": "string", + "metadata": { + "description": "Required. Defines the version of the rule set to use." + } + }, + "ruleGroupOverrides": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Defines the rule group overrides to apply to the rule set." + } + }, + "exclusions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Describes the exclusions that are applied to all rules in the set." + } + }, + "ruleSetAction": { + "type": "string", + "allowedValues": [ + "Block", + "Log", + "Redirect" + ], + "nullable": true, + "metadata": { + "description": "Optional. Defines the rule set action." + } + } + } + }, + "nullable": true + }, + "customRulesType": { + "type": "object", + "properties": { + "rules": { + "$ref": "#/definitions/customRulesRuleType", + "metadata": { + "description": "Optional. List of rules." + } + } + } + }, + "customRulesRuleType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "string", + "allowedValues": [ + "Allow", + "Block", + "Log", + "Redirect" + ], + "metadata": { + "description": "Required. Describes what action to be applied when rule matches." + } + }, + "enabledState": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. Describes if the custom rule is in enabled or disabled state." + } + }, + "matchConditions": { + "type": "array", + "metadata": { + "description": "Required. List of match conditions. See https://learn.microsoft.com/en-us/azure/templates/microsoft.network/frontdoorwebapplicationfirewallpolicies#matchcondition for details." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Describes the name of the rule." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. Describes priority of the rule. Rules with a lower value will be evaluated before rules with a higher value." + } + }, + "rateLimitDurationInMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Time window for resetting the rate limit count. Default is 1 minute." + } + }, + "rateLimitThreshold": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Number of allowed requests per client within the time window." + } + }, + "ruleType": { + "type": "string", + "allowedValues": [ + "MatchRule", + "RateLimitRule" + ], + "metadata": { + "description": "Required. Describes type of rule." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -154,7 +296,7 @@ } }, "managedRules": { - "type": "object", + "$ref": "#/definitions/managedRulesType", "defaultValue": { "managedRuleSets": [ { @@ -177,7 +319,7 @@ } }, "customRules": { - "type": "object", + "$ref": "#/definitions/customRulesType", "defaultValue": { "rules": [ { @@ -265,7 +407,7 @@ }, "frontDoorWAFPolicy": { "type": "Microsoft.Network/FrontDoorWebApplicationFirewallPolicies", - "apiVersion": "2022-05-01", + "apiVersion": "2024-02-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "sku": { @@ -342,7 +484,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('frontDoorWAFPolicy', '2022-05-01', 'full').location]" + "value": "[reference('frontDoorWAFPolicy', '2024-02-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/network/front-door/ORPHANED.md b/avm/res/network/front-door/ORPHANED.md deleted file mode 100644 index ef8fa911d2..0000000000 --- a/avm/res/network/front-door/ORPHANED.md +++ /dev/null @@ -1,4 +0,0 @@ -⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ - -- Only security and bug fixes are being handled by the AVM core team at present. -- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/network/front-door/README.md b/avm/res/network/front-door/README.md index 1fc4d43721..b68647da31 100644 --- a/avm/res/network/front-door/README.md +++ b/avm/res/network/front-door/README.md @@ -1,10 +1,5 @@ # Azure Front Doors `[Microsoft.Network/frontDoors]` -> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ -> -> - Only security and bug fixes are being handled by the AVM core team at present. -> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! - This module deploys an Azure Front Door. ## Navigation @@ -22,7 +17,7 @@ This module deploys an Azure Front Door. | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Network/frontDoors` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2020-05-01/frontDoors) | +| `Microsoft.Network/frontDoors` | [2021-06-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2021-06-01/frontDoors) | ## Usage examples @@ -141,7 +136,7 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -252,6 +247,101 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door:' + +// Required parameters +param backendPools = [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } +] +param frontendEndpoints = [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } +] +param healthProbeSettings = [ + { + name: 'heathProbe' + properties: { + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } +] +param loadBalancingSettings = [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } +] +param name = '' +param routingRules = [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + } + } + } +] +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -413,7 +503,7 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -592,6 +682,157 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door:' + +// Required parameters +param backendPools = [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } +] +param frontendEndpoints = [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } +] +param healthProbeSettings = [ + { + name: 'heathProbe' + properties: { + enabledState: '' + healthProbeMethod: '' + intervalInSeconds: 60 + path: '/' + protocol: 'Https' + } + } +] +param loadBalancingSettings = [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } +] +param name = '' +param routingRules = [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + forwardingProtocol: 'MatchRequest' + } + } + } +] +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'FrontdoorAccessLog' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enforceCertificateNameCheck = 'Disabled' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'b2c1ef5f-3422-4a49-8e55-7789fe980b64' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sendRecvTimeoutSeconds = 10 +param tags = { + 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. @@ -719,7 +960,7 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -860,6 +1101,123 @@ module frontDoor 'br/public:avm/res/network/front-door:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/front-door:' + +// Required parameters +param backendPools = [ + { + name: 'backendPool' + properties: { + backends: [ + { + address: 'biceptest.local' + backendHostHeader: 'backendAddress' + enabledState: 'Enabled' + httpPort: 80 + httpsPort: 443 + priority: 1 + privateLinkAlias: '' + privateLinkApprovalMessage: '' + privateLinkLocation: '' + weight: 50 + } + ] + HealthProbeSettings: { + id: '' + } + LoadBalancingSettings: { + id: '' + } + } + } +] +param frontendEndpoints = [ + { + name: 'frontEnd' + properties: { + hostName: '' + sessionAffinityEnabledState: 'Disabled' + sessionAffinityTtlSeconds: 60 + } + } +] +param healthProbeSettings = [ + { + name: 'heathProbe' + properties: { + enabledState: 'Enabled' + healthProbeMethod: 'HEAD' + intervalInSeconds: 60 + path: '/healthz' + protocol: 'Https' + } + } +] +param loadBalancingSettings = [ + { + name: 'loadBalancer' + properties: { + additionalLatencyMilliseconds: 0 + sampleSize: 50 + successfulSamplesRequired: 1 + } + } +] +param name = '' +param routingRules = [ + { + name: 'routingRule' + properties: { + acceptedProtocols: [ + 'Http' + 'Https' + ] + enabledState: 'Enabled' + frontendEndpoints: [ + { + id: '' + } + ] + patternsToMatch: [ + '/*' + ] + routeConfiguration: { + '@odata.type': '#Microsoft.Azure.FrontDoor.Models.FrontdoorForwardingConfiguration' + backendPool: { + id: '' + } + forwardingProtocol: 'MatchRequest' + } + } + } +] +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enforceCertificateNameCheck = 'Disabled' +param location = '' +param sendRecvTimeoutSeconds = 10 +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1157,6 +1515,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/front-door/main.bicep b/avm/res/network/front-door/main.bicep index 6e47218f83..4ea7e31e76 100644 --- a/avm/res/network/front-door/main.bicep +++ b/avm/res/network/front-door/main.bicep @@ -101,7 +101,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource frontDoor 'Microsoft.Network/frontDoors@2020-05-01' = { +resource frontDoor 'Microsoft.Network/frontDoors@2021-06-01' = { name: name location: 'global' tags: tags diff --git a/avm/res/network/front-door/main.json b/avm/res/network/front-door/main.json index 9a41829948..6e1554fd90 100644 --- a/avm/res/network/front-door/main.json +++ b/avm/res/network/front-door/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "1188225161775362575" + "templateHash": "3109919695748867092" }, "name": "Azure Front Doors", "description": "This module deploys an Azure Front Door.", @@ -380,7 +380,7 @@ }, "frontDoor": { "type": "Microsoft.Network/frontDoors", - "apiVersion": "2020-05-01", + "apiVersion": "2021-06-01", "name": "[parameters('name')]", "location": "global", "tags": "[parameters('tags')]", diff --git a/avm/res/network/ip-group/README.md b/avm/res/network/ip-group/README.md index 211d8de421..d8c0ac67b6 100644 --- a/avm/res/network/ip-group/README.md +++ b/avm/res/network/ip-group/README.md @@ -56,7 +56,7 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ip-group:' + +// Required parameters +param name = 'nigmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -136,7 +152,7 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -198,6 +214,54 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ip-group:' + +// Required parameters +param name = 'nigmax001' +// Non-required parameters +param ipAddresses = [ + '10.0.0.1' + '10.0.0.2' +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '26438d40-c8be-4229-ba65-800cf4e49dc8' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -233,7 +297,7 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -268,6 +332,31 @@ module ipGroup 'br/public:avm/res/network/ip-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/ip-group:' + +// Required parameters +param name = 'nigwaf001' +// Non-required parameters +param ipAddresses = [ + '10.0.0.1' + '10.0.0.2' +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -360,6 +449,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'IPAM Pool Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/load-balancer/README.md b/avm/res/network/load-balancer/README.md index 2ca817beb0..51bbc3fbdb 100644 --- a/avm/res/network/load-balancer/README.md +++ b/avm/res/network/load-balancer/README.md @@ -68,7 +68,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -98,6 +98,28 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } +] +param name = 'nlbmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using external load balancer parameter_ This instance deploys the module with an externally facing load balancer. @@ -245,7 +267,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -408,6 +430,143 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } +] +param name = 'nlbext001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundRules = [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } +] +param probes = [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Http' + requestPath: '/http-probe' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/https-probe' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using internal load balancer parameter_ This instance deploys the module with the minimum set of required parameters to deploy an internal load balancer. @@ -511,7 +670,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -626,6 +785,99 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'privateIPConfig1' + subnetId: '' + } +] +param name = 'nlbint001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'servers' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } +] +param location = '' +param probes = [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } +] +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -779,7 +1031,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -948,6 +1200,149 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'publicIPConfig1' + publicIPAddressId: '' + } +] +param name = 'nlbmax001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'backendAddressPool1' + } + { + name: 'backendAddressPool2' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendPort: 3389 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 3389 + name: 'inboundNatRule2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'backendAddressPool1' + backendPort: 80 + disableOutboundSnat: true + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 80 + idleTimeoutInMinutes: 5 + loadDistribution: 'Default' + name: 'publicIPLBRule1' + probeName: 'probe1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'backendAddressPool2' + backendPort: 8080 + frontendIPConfigurationName: 'publicIPConfig1' + frontendPort: 8080 + loadDistribution: 'Default' + name: 'publicIPLBRule2' + probeName: 'probe2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param outboundRules = [ + { + allocatedOutboundPorts: 63984 + backendAddressPoolName: 'backendAddressPool1' + frontendIPConfigurationName: 'publicIPConfig1' + name: 'outboundRule1' + } +] +param probes = [ + { + intervalInSeconds: 10 + name: 'probe1' + numberOfProbes: 5 + port: 80 + protocol: 'Tcp' + } + { + name: 'probe2' + port: 443 + protocol: 'Https' + requestPath: '/' + } +] +param roleAssignments = [ + { + name: '3a5b2a4a-3584-4d6b-9cf0-ceb1e4f88a5d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module with the minimum set of required parameters to deploy a WAF-aligned internal load balancer. @@ -1057,7 +1452,7 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1178,6 +1573,105 @@ module loadBalancer 'br/public:avm/res/network/load-balancer:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/load-balancer:' + +// Required parameters +param frontendIPConfigurations = [ + { + name: 'privateIPConfig1' + subnetId: '' + zones: [ + 1 + 2 + 3 + ] + } +] +param name = 'nlbwaf001' +// Non-required parameters +param backendAddressPools = [ + { + name: 'servers' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param inboundNatRules = [ + { + backendPort: 443 + enableFloatingIP: false + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 443 + idleTimeoutInMinutes: 4 + name: 'inboundNatRule1' + protocol: 'Tcp' + } + { + backendAddressPoolName: 'servers' + backendPort: 3389 + frontendIPConfigurationName: 'privateIPConfig1' + frontendPortRangeEnd: 5010 + frontendPortRangeStart: 5000 + loadDistribution: 'Default' + name: 'inboundNatRule2' + probeName: 'probe2' + } +] +param loadBalancingRules = [ + { + backendAddressPoolName: 'servers' + backendPort: 0 + disableOutboundSnat: true + enableFloatingIP: true + enableTcpReset: false + frontendIPConfigurationName: 'privateIPConfig1' + frontendPort: 0 + idleTimeoutInMinutes: 4 + loadDistribution: 'Default' + name: 'privateIPLBRule1' + probeName: 'probe1' + protocol: 'All' + } +] +param location = '' +param probes = [ + { + intervalInSeconds: 5 + name: 'probe1' + numberOfProbes: 2 + port: '62000' + protocol: 'Tcp' + } +] +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1459,6 +1953,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/local-network-gateway/README.md b/avm/res/network/local-network-gateway/README.md index 0e702b10ed..eeac57706a 100644 --- a/avm/res/network/local-network-gateway/README.md +++ b/avm/res/network/local-network-gateway/README.md @@ -60,7 +60,7 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -90,6 +90,26 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/local-network-gateway:' + +// Required parameters +param localAddressPrefixes = [ + '192.168.1.0/24' +] +param localGatewayPublicIpAddress = '8.8.8.8' +param name = 'nlngmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -150,7 +170,7 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -220,6 +240,56 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/local-network-gateway:' + +// Required parameters +param localAddressPrefixes = [ + '192.168.1.0/24' +] +param localGatewayPublicIpAddress = '8.8.8.8' +param name = 'nlngmax001' +// Non-required parameters +param localAsn = '65123' +param localBgpPeeringAddress = '192.168.1.5' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'd14a9fe8-2358-434a-a715-3d10978088cc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -261,7 +331,7 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -310,6 +380,37 @@ module localNetworkGateway 'br/public:avm/res/network/local-network-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/local-network-gateway:' + +// Required parameters +param localAddressPrefixes = [ + '192.168.1.0/24' +] +param localGatewayPublicIpAddress = '8.8.8.8' +param name = 'nlngwaf001' +// Non-required parameters +param localAsn = '65123' +param localBgpPeeringAddress = '192.168.1.5' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -445,6 +546,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/nat-gateway/README.md b/avm/res/network/nat-gateway/README.md index ed01e1d452..48846ff683 100644 --- a/avm/res/network/nat-gateway/README.md +++ b/avm/res/network/nat-gateway/README.md @@ -31,9 +31,10 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/nat-gateway:`. - [Using only defaults](#example-1-using-only-defaults) -- [Using large parameter set](#example-2-using-large-parameter-set) -- [Combine a generated and provided Public IP Prefix](#example-3-combine-a-generated-and-provided-public-ip-prefix) -- [WAF-aligned](#example-4-waf-aligned) +- [Using an existing Public IP](#example-2-using-an-existing-public-ip) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Combine a generated and provided Public IP Prefix](#example-4-combine-a-generated-and-provided-public-ip-prefix) +- [WAF-aligned](#example-5-waf-aligned) ### Example 1: _Using only defaults_ @@ -62,7 +63,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -87,7 +88,98 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -### Example 2: _Using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngmin001' +param zone = 1 +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 2: _Using an existing Public IP_ + +This instance deploys the module using an existing Public IP address. + + +

    + +via Bicep module + +```bicep +module natGateway 'br/public:avm/res/network/nat-gateway:' = { + name: 'natGatewayDeployment' + params: { + // Required parameters + name: 'nngepip001' + zone: 1 + // Non-required parameters + location: '' + publicIpResourceIds: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nngepip001" + }, + "zone": { + "value": 1 + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIpResourceIds": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngepip001' +param zone = 1 +// Non-required parameters +param location = '' +param publicIpResourceIds = '' +``` + +
    +

    + +### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -184,7 +276,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -287,7 +379,94 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -### Example 3: _Combine a generated and provided Public IP Prefix_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngmax001' +param zone = 1 +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressObjects = [ + { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nngmax001-pip' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + } +] +param roleAssignments = [ + { + name: '69d7ed51-8af4-4eed-bcea-bdadcccb1200' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + +### Example 4: _Combine a generated and provided Public IP Prefix_ This example shows how you can provide a Public IP Prefix to the module, while also generating one in the module. @@ -323,7 +502,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -359,7 +538,33 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -### Example 4: _WAF-aligned_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngcprx001' +param zone = 0 +// Non-required parameters +param location = '' +param publicIPPrefixObjects = [ + { + name: 'nngcprx001-pippre' + prefixLength: 30 + tags: { + 'hidden-title': 'CustomTag' + } + } +] +``` + +
    +

    + +### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -420,7 +625,7 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -485,6 +690,57 @@ module natGateway 'br/public:avm/res/network/nat-gateway:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/nat-gateway:' + +// Required parameters +param name = 'nngwaf001' +param zone = 1 +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressObjects = [ + { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'nngwaf001-pip' + skuTier: 'Regional' + zones: [ + 1 + 2 + 3 + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -628,6 +884,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/nat-gateway/main.bicep b/avm/res/network/nat-gateway/main.bicep index 8836c815fe..f576caedd5 100644 --- a/avm/res/network/nat-gateway/main.bicep +++ b/avm/res/network/nat-gateway/main.bicep @@ -99,7 +99,7 @@ module publicIPAddresses 'br/public:avm/res/network/public-ip-address:0.5.1' = [ for (publicIPAddressObject, index) in (publicIPAddressObjects ?? []): { name: '${uniqueString(deployment().name, location)}-NatGw-PIP-${index}' params: { - name: contains(publicIPAddressObject, 'name') ? publicIPAddressObject.name : '${name}-pip' + name: publicIPAddressObject.?name ?? '${name}-pip' location: location lock: publicIPAddressObject.?lock ?? lock diagnosticSettings: publicIPAddressObject.?diagnosticSettings @@ -133,7 +133,7 @@ module publicIPPrefixes 'br/public:avm/res/network/public-ip-prefix:0.4.1' = [ for (publicIPPrefixObject, index) in (publicIPPrefixObjects ?? []): { name: '${uniqueString(deployment().name, location)}-NatGw-Prefix-PIP-${index}' params: { - name: contains(publicIPPrefixObject, 'name') ? publicIPPrefixObject.name : '${name}-pip' + name: publicIPPrefixObject.?name ?? '${name}-pip' location: location lock: publicIPPrefixObject.?lock ?? lock prefixLength: publicIPPrefixObject.prefixLength diff --git a/avm/res/network/nat-gateway/main.json b/avm/res/network/nat-gateway/main.json index 414a6e0129..588a626b30 100644 --- a/avm/res/network/nat-gateway/main.json +++ b/avm/res/network/nat-gateway/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3430947452943320440" + "version": "0.30.3.12046", + "templateHash": "16462612640291787003" }, "name": "NAT Gateways", "description": "This module deploys a NAT Gateway.", @@ -308,7 +308,9 @@ }, "mode": "Incremental", "parameters": { - "name": "[if(contains(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'name'), createObject('value', coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()].name), createObject('value', format('{0}-pip', parameters('name'))))]", + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPAddressObjects'), createArray())[copyIndex()], 'name'), format('{0}-pip', parameters('name')))]" + }, "location": { "value": "[parameters('location')]" }, @@ -1004,8 +1006,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15040145942768763519" + "version": "0.30.3.12046", + "templateHash": "9121047532434826411" } }, "parameters": { @@ -1050,7 +1052,9 @@ }, "mode": "Incremental", "parameters": { - "name": "[if(contains(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'name'), createObject('value', coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()].name), createObject('value', format('{0}-pip', parameters('name'))))]", + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('publicIPPrefixObjects'), createArray())[copyIndex()], 'name'), format('{0}-pip', parameters('name')))]" + }, "location": { "value": "[parameters('location')]" }, @@ -1416,8 +1420,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15040145942768763519" + "version": "0.30.3.12046", + "templateHash": "9121047532434826411" } }, "parameters": { diff --git a/avm/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep b/avm/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep new file mode 100644 index 0000000000..d12b008b0c --- /dev/null +++ b/avm/res/network/nat-gateway/tests/e2e/existingPip/dependencies.bicep @@ -0,0 +1,25 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Public IP to create.') +param existingPipName string + +resource existingPip 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: existingPipName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the existing Public IP.') +output existingPipResourceId string = existingPip.id diff --git a/avm/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep b/avm/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep new file mode 100644 index 0000000000..1b13848208 --- /dev/null +++ b/avm/res/network/nat-gateway/tests/e2e/existingPip/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Using an existing Public IP' +metadata description = 'This instance deploys the module using an existing Public IP address.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.natgateway-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nngepip' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + existingPipName: '${namePrefix}${serviceShort}001-existingpip1' + + } +} + + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + zone: 1 + publicIpResourceIds: [nestedDependencies.outputs.existingPipResourceId] + } + } +] diff --git a/avm/res/network/network-interface/README.md b/avm/res/network/network-interface/README.md index 3e9767ba44..a9368e2156 100644 --- a/avm/res/network/network-interface/README.md +++ b/avm/res/network/network-interface/README.md @@ -63,7 +63,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,28 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-interface:' + +// Required parameters +param ipConfigurations = [ + { + name: 'ipconfig01' + subnetResourceId: '' + } +] +param name = 'nnimin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -180,7 +202,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -273,6 +295,83 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-interface:' + +// Required parameters +param ipConfigurations = [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + subnetResourceId: '' + } + { + applicationSecurityGroups: [ + { + id: '' + } + ] + subnetResourceId: '' + } +] +param name = 'nnimax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '026b830f-441f-469a-8cf3-c3ea9f5bcfe1' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 Well-Architected Framework. @@ -337,7 +436,7 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -403,6 +502,60 @@ module networkInterface 'br/public:avm/res/network/network-interface:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-interface:' + +// Required parameters +param ipConfigurations = [ + { + applicationSecurityGroups: [ + { + id: '' + } + ] + loadBalancerBackendAddressPools: [ + { + id: '' + } + ] + name: 'ipconfig01' + subnetResourceId: '' + } + { + applicationSecurityGroups: [ + { + id: '' + } + ] + subnetResourceId: '' + } +] +param name = 'nniwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -722,6 +875,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/network-manager/README.md b/avm/res/network/network-manager/README.md index 99f4273940..cbff3f3f1f 100644 --- a/avm/res/network/network-manager/README.md +++ b/avm/res/network/network-manager/README.md @@ -72,7 +72,7 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -106,6 +106,30 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = 'nnmmin001' +param networkManagerScopeAccesses = [ + 'Connectivity' +] +param networkManagerScopes = { + subscriptions: [ + '' + ] +} +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -362,7 +386,7 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -632,6 +656,252 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = '' +param networkManagerScopeAccesses = [ + 'Connectivity' + 'SecurityAdmin' +] +param networkManagerScopes = { + managementGroups: [ + '/providers/Microsoft.Management/managementGroups/#_managementGroupId_#' + ] +} +// Non-required parameters +param connectivityConfigurations = [ + { + appliesToGroups: [ + { + groupConnectivity: 'None' + isGlobal: false + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'HubAndSpoke' + deleteExistingPeering: true + description: 'hubSpokeConnectivity description' + hubs: [ + { + resourceId: '' + resourceType: 'Microsoft.Network/virtualNetworks' + } + ] + isGlobal: false + name: 'hubSpokeConnectivity' + } + { + appliesToGroups: [ + { + groupConnectivity: 'DirectlyConnected' + isGlobal: true + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'Mesh' + deleteExistingPeering: true + description: 'MeshConnectivity description' + isGlobal: true + name: 'MeshConnectivity-1' + } + { + appliesToGroups: [ + { + groupConnectivity: 'DirectlyConnected' + isGlobal: false + networkGroupResourceId: '' + useHubGateway: false + } + ] + connectivityTopology: 'Mesh' + isGlobal: false + name: 'MeshConnectivity-2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkGroups = [ + { + description: 'network-group-spokes description' + name: 'network-group-spokes-1' + staticMembers: [ + { + name: 'virtualNetworkSpoke1' + resourceId: '' + } + { + name: 'virtualNetworkSpoke2' + resourceId: '' + } + ] + } + { + name: 'network-group-spokes-2' + staticMembers: [ + { + name: 'virtualNetworkSpoke3' + resourceId: '' + } + ] + } + { + name: 'network-group-spokes-3' + } +] +param roleAssignments = [ + { + name: 'e8472331-308c-4c77-aa31-017279d8e5b6' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scopeConnections = [ + { + description: 'description of the scope connection' + name: 'scope-connection-test' + resourceId: '' + tenantId: '' + } +] +param securityAdminConfigurations = [ + { + applyOnNetworkIntentPolicyBasedServices: [ + 'AllowRulesOnly' + ] + description: 'description of the security admin config' + name: 'test-security-admin-config-1' + ruleCollections: [ + { + appliesToGroups: [ + { + networkGroupResourceId: '' + } + ] + description: 'test-rule-collection-description' + name: 'test-rule-collection-1' + rules: [ + { + access: 'Allow' + description: 'test-inbound-allow-rule-1-description' + direction: 'Inbound' + name: 'test-inbound-allow-rule-1' + priority: 150 + protocol: 'Tcp' + } + { + access: 'Deny' + description: 'test-outbound-deny-rule-2-description' + direction: 'Outbound' + name: 'test-outbound-deny-rule-2' + priority: 200 + protocol: 'Tcp' + sourcePortRanges: [ + '442-445' + '80' + ] + sources: [ + { + addressPrefix: 'AppService.WestEurope' + addressPrefixType: 'ServiceTag' + } + ] + } + ] + } + { + appliesToGroups: [ + { + networkGroupResourceId: '' + } + { + networkGroupResourceId: '' + } + ] + name: 'test-rule-collection-2' + rules: [ + { + access: 'Allow' + destinationPortRanges: [ + '442-445' + '80' + ] + destinations: [ + { + addressPrefix: '192.168.20.20' + addressPrefixType: 'IPPrefix' + } + ] + direction: 'Inbound' + name: 'test-inbound-allow-rule-3' + priority: 250 + protocol: 'Tcp' + } + { + access: 'Allow' + description: 'test-inbound-allow-rule-4-description' + destinations: [ + { + addressPrefix: '172.16.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '172.16.1.0/24' + addressPrefixType: 'IPPrefix' + } + ] + direction: 'Inbound' + name: 'test-inbound-allow-rule-4' + priority: 260 + protocol: 'Tcp' + sources: [ + { + addressPrefix: '10.0.0.0/24' + addressPrefixType: 'IPPrefix' + } + { + addressPrefix: '100.100.100.100' + addressPrefixType: 'IPPrefix' + } + ] + } + ] + } + ] + } +] +param tags = { + 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. @@ -671,7 +941,7 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -712,6 +982,35 @@ module networkManager 'br/public:avm/res/network/network-manager:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-manager:' + +// Required parameters +param name = 'nnmwaf001' +param networkManagerScopeAccesses = [ + 'SecurityAdmin' +] +param networkManagerScopes = { + subscriptions: [ + '' + ] +} +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1075,6 +1374,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'IPAM Pool Contributor'` + - `'LocalNGFirewallAdministrator role'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/network-security-group/README.md b/avm/res/network/network-security-group/README.md index 15b057b8ce..5fa87016be 100644 --- a/avm/res/network/network-security-group/README.md +++ b/avm/res/network/network-security-group/README.md @@ -57,7 +57,7 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-security-group:' + +// Required parameters +param name = 'nnsgmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -231,7 +247,7 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -389,6 +405,148 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-security-group:' + +// Required parameters +param name = 'nnsgmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'b6d38ee8-4058-42b1-af6a-b8d585cf61ef' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securityRules = [ + { + name: 'Specific' + properties: { + access: 'Allow' + description: 'Tests specific IPs and ports' + destinationAddressPrefix: '*' + destinationPortRange: '8080' + direction: 'Inbound' + priority: 100 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Ranges' + properties: { + access: 'Allow' + description: 'Tests Ranges' + destinationAddressPrefixes: [ + '10.2.0.0/16' + '10.3.0.0/16' + ] + destinationPortRanges: [ + '90' + '91' + ] + direction: 'Inbound' + priority: 101 + protocol: '*' + sourceAddressPrefixes: [ + '10.0.0.0/16' + '10.1.0.0/16' + ] + sourcePortRanges: [ + '80' + '81' + ] + } + } + { + name: 'Port_8082' + properties: { + access: 'Allow' + description: 'Allow inbound access on TCP 8082' + destinationApplicationSecurityGroupResourceIds: [ + '' + ] + destinationPortRange: '8082' + direction: 'Inbound' + priority: 102 + protocol: '*' + sourceApplicationSecurityGroupResourceIds: [ + '' + ] + sourcePortRange: '*' + } + } + { + name: 'Deny-All-Inbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRange: '*' + direction: 'Inbound' + priority: 4095 + protocol: '*' + sourceAddressPrefix: '*' + sourcePortRange: '*' + } + } + { + name: 'Allow-AzureCloud-Tcp' + properties: { + access: 'Allow' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + direction: 'Outbound' + priority: 250 + protocol: 'Tcp' + sourceAddressPrefixes: [ + '10.10.10.0/24' + '192.168.1.0/24' + ] + sourcePortRange: '*' + } + } +] +param tags = { + 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. @@ -438,7 +596,7 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -487,6 +645,45 @@ module networkSecurityGroup 'br/public:avm/res/network/network-security-group:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-security-group:' + +// Required parameters +param name = 'nnsgwaf001' +// Non-required parameters +param location = '' +param securityRules = [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -693,6 +890,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/network-watcher/README.md b/avm/res/network/network-watcher/README.md index a13c4ae45b..f35d694880 100644 --- a/avm/res/network/network-watcher/README.md +++ b/avm/res/network/network-watcher/README.md @@ -55,7 +55,7 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -72,6 +72,19 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-watcher:' + +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -189,7 +202,7 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -310,6 +323,113 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-watcher:' + +param 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()' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } +] +param flowLogs = [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwmax-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } +] +param location = '' +param name = '' +param roleAssignments = [ + { + name: 'e8e93fb7-f450-41d5-ae86-a32d34e72578' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -408,7 +528,7 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -508,6 +628,94 @@ module networkWatcher 'br/public:avm/res/network/network-watcher:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/network-watcher:' + +param 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()' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } +] +param flowLogs = [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwwaf-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } +] +param location = '' +param name = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Optional parameters** @@ -605,6 +813,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/README.md b/avm/res/network/private-dns-zone/README.md index b9bcac8c5e..bc18b62e9c 100644 --- a/avm/res/network/private-dns-zone/README.md +++ b/avm/res/network/private-dns-zone/README.md @@ -65,7 +65,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -87,6 +87,22 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-dns-zone:' + +// Required parameters +param name = 'npdzmin001.com' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -362,7 +378,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -657,6 +673,271 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-dns-zone:' + +// Required parameters +param name = 'npdzmax001.com' +// Non-required parameters +param a = [ + { + aRecords: [ + { + ipv4Address: '10.240.4.4' + } + ] + name: 'A_10.240.4.4' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param aaaa = [ + { + aaaaRecords: [ + { + ipv6Address: '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + } + ] + name: 'AAAA_2001_0db8_85a3_0000_0000_8a2e_0370_7334' + ttl: 3600 + } +] +param cname = [ + { + cnameRecord: { + cname: 'test' + } + name: 'CNAME_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param mx = [ + { + mxRecords: [ + { + exchange: 'contoso.com' + preference: 100 + } + ] + name: 'MX_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param ptr = [ + { + name: 'PTR_contoso' + ptrRecords: [ + { + ptrdname: 'contoso.com' + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + } +] +param roleAssignments = [ + { + name: '8001f03c-2ca1-4dab-ab69-4dbaa3635af1' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param soa = [ + { + name: '@' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + soaRecord: { + email: 'azureprivatedns-host.microsoft.com' + expireTime: 2419200 + host: 'azureprivatedns.net' + minimumTtl: 10 + refreshTime: 3600 + retryTime: 300 + serialNumber: 1 + } + ttl: 3600 + } +] +param srv = [ + { + name: 'SRV_contoso' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + srvRecords: [ + { + port: 9332 + priority: 0 + target: 'test.contoso.com' + weight: 0 + } + ] + ttl: 3600 + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param txt = [ + { + name: 'TXT_test' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + ttl: 3600 + txtRecords: [ + { + value: [ + 'test' + ] + } + ] + } +] +param virtualNetworkLinks = [ + { + registrationEnabled: true + virtualNetworkResourceId: '' + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -692,7 +973,7 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -727,6 +1008,31 @@ module privateDnsZone 'br/public:avm/res/network/private-dns-zone:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-dns-zone:' + +// Required parameters +param name = 'npdzwaf001.com' +// Non-required parameters +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -823,6 +1129,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -983,6 +1297,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1143,6 +1465,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1363,6 +1693,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1523,6 +1861,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1627,6 +1973,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** @@ -1760,6 +2113,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1968,6 +2329,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2159,6 +2528,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/a/README.md b/avm/res/network/private-dns-zone/a/README.md index 1d776a8b07..6584b4966c 100644 --- a/avm/res/network/private-dns-zone/a/README.md +++ b/avm/res/network/private-dns-zone/a/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/aaaa/README.md b/avm/res/network/private-dns-zone/aaaa/README.md index 8eb2f75a00..01b9ca1fbe 100644 --- a/avm/res/network/private-dns-zone/aaaa/README.md +++ b/avm/res/network/private-dns-zone/aaaa/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/cname/README.md b/avm/res/network/private-dns-zone/cname/README.md index 0e3cba5ca8..bcabc2f0a8 100644 --- a/avm/res/network/private-dns-zone/cname/README.md +++ b/avm/res/network/private-dns-zone/cname/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/mx/README.md b/avm/res/network/private-dns-zone/mx/README.md index 3284c3e1e7..721b698ccd 100644 --- a/avm/res/network/private-dns-zone/mx/README.md +++ b/avm/res/network/private-dns-zone/mx/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/ptr/README.md b/avm/res/network/private-dns-zone/ptr/README.md index 23549d6a1f..0c8d412a53 100644 --- a/avm/res/network/private-dns-zone/ptr/README.md +++ b/avm/res/network/private-dns-zone/ptr/README.md @@ -72,6 +72,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/soa/README.md b/avm/res/network/private-dns-zone/soa/README.md index 5936d5e83c..fd6c40a7fb 100644 --- a/avm/res/network/private-dns-zone/soa/README.md +++ b/avm/res/network/private-dns-zone/soa/README.md @@ -65,6 +65,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/srv/README.md b/avm/res/network/private-dns-zone/srv/README.md index 01a7f68037..a6047c6bda 100644 --- a/avm/res/network/private-dns-zone/srv/README.md +++ b/avm/res/network/private-dns-zone/srv/README.md @@ -65,6 +65,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-dns-zone/txt/README.md b/avm/res/network/private-dns-zone/txt/README.md index 5439d372f2..2121b15b16 100644 --- a/avm/res/network/private-dns-zone/txt/README.md +++ b/avm/res/network/private-dns-zone/txt/README.md @@ -65,6 +65,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Private DNS Zone Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/private-endpoint/README.md b/avm/res/network/private-endpoint/README.md index 9aa9d1085e..3db54f7e96 100644 --- a/avm/res/network/private-endpoint/README.md +++ b/avm/res/network/private-endpoint/README.md @@ -70,7 +70,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -108,6 +108,34 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npemin001' +param subnetResourceId = '' +// Non-required parameters +param location = '' +param privateLinkServiceConnections = [ + { + name: 'npemin001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + } + } +] +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -206,7 +234,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -320,6 +348,94 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npemax001' +param subnetResourceId = '' +// Non-required parameters +param applicationSecurityGroupResourceIds = [ + '' +] +param customDnsConfigs = [ + { + fqdn: 'abc.keyvault.com' + ipAddresses: [ + '10.0.0.10' + ] + } +] +param customNetworkInterfaceName = 'npemax001nic' +param ipConfigurations = [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateDnsZoneGroup = { + name: 'default' + privateDnsZoneGroupConfigs: [ + { + name: 'config' + privateDnsZoneResourceId: '' + } + ] +} +param privateLinkServiceConnections = [ + { + name: 'npemax001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + requestMessage: 'Hey there' + } + } +] +param roleAssignments = [ + { + name: '6804f270-b4e9-455f-a11b-7f2a64e38f7c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using private link service_ This instance deploys the module with a private link service to test the application of an empty list of string for `groupIds`. @@ -366,7 +482,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -414,6 +530,42 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npepls001' +param subnetResourceId = '' +// Non-required parameters +param ipConfigurations = [ + { + name: 'myIPconfig' + properties: { + groupId: '' + memberName: '' + privateIPAddress: '10.0.0.10' + } + } +] +param location = '' +param privateLinkServiceConnections = [ + { + name: 'npepls001' + properties: { + groupIds: [] + privateLinkServiceId: '' + } + } +] +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -482,7 +634,7 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -562,6 +714,64 @@ module privateEndpoint 'br/public:avm/res/network/private-endpoint:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-endpoint:' + +// Required parameters +param name = 'npewaf001' +param subnetResourceId = '' +// Non-required parameters +param applicationSecurityGroupResourceIds = [ + '' +] +param customNetworkInterfaceName = 'npewaf001nic' +param ipConfigurations = [ + { + name: 'myIPconfig' + properties: { + groupId: 'vault' + memberName: 'default' + privateIPAddress: '10.0.0.10' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateDnsZoneGroup = { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] +} +param privateLinkServiceConnections = [ + { + name: 'npewaf001' + properties: { + groupIds: [ + 'vault' + ] + privateLinkServiceId: '' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -942,6 +1152,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/private-link-service/README.md b/avm/res/network/private-link-service/README.md index 1cf7759826..53aea96467 100644 --- a/avm/res/network/private-link-service/README.md +++ b/avm/res/network/private-link-service/README.md @@ -71,7 +71,7 @@ module privateLinkService 'br/public:avm/res/network/private-link-service: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -112,6 +112,37 @@ module privateLinkService 'br/public:avm/res/network/private-link-service:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-link-service:' + +// Required parameters +param ipConfigurations = [ + { + name: 'nplsmin01' + properties: { + subnet: { + id: '' + } + } + } +] +param loadBalancerFrontendIpConfigurations = [ + { + id: '' + } +] +param name = 'nplsmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -198,7 +229,7 @@ module privateLinkService 'br/public:avm/res/network/private-link-service: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -298,6 +329,82 @@ module privateLinkService 'br/public:avm/res/network/private-link-service:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-link-service:' + +// Required parameters +param ipConfigurations = [ + { + name: 'nplsmax01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } +] +param loadBalancerFrontendIpConfigurations = [ + { + id: '' + } +] +param name = 'nplsmax001' +// Non-required parameters +param autoApproval = { + subscriptions: [ + '*' + ] +} +param enableProxyProtocol = true +param fqdns = [ + 'nplsmax.plsfqdn01.azure.privatelinkservice' + 'nplsmax.plsfqdn02.azure.privatelinkservice' +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'fec82bb5-8552-4c4b-a3f6-65bdae54d7f4' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = { + subscriptions: [ + '' + ] +} +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -361,7 +468,7 @@ module privateLinkService 'br/public:avm/res/network/private-link-service: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -434,6 +541,59 @@ module privateLinkService 'br/public:avm/res/network/private-link-service:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/private-link-service:' + +// Required parameters +param ipConfigurations = [ + { + name: 'nplswaf01' + properties: { + primary: true + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: '' + } + } + } +] +param loadBalancerFrontendIpConfigurations = [ + { + id: '' + } +] +param name = 'nplswaf001' +// Non-required parameters +param autoApproval = { + subscriptions: [ + '*' + ] +} +param enableProxyProtocol = true +param fqdns = [ + 'nplswaf.plsfqdn01.azure.privatelinkservice' + 'nplswaf.plsfqdn02.azure.privatelinkservice' +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param visibility = { + subscriptions: [ + '' + ] +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -570,6 +730,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/public-ip-address/README.md b/avm/res/network/public-ip-address/README.md index 9f4526d01e..8ba95ec8ab 100644 --- a/avm/res/network/public-ip-address/README.md +++ b/avm/res/network/public-ip-address/README.md @@ -57,7 +57,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-address:' + +// Required parameters +param name = 'npiamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -154,7 +170,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -249,6 +265,71 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-address:' + +// Required parameters +param name = 'npiamax001' +// Non-required parameters +param ddosSettings = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsSettings = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressVersion = 'IPv4' +param publicIPAllocationMethod = 'Static' +param publicIpPrefixResourceId = '' +param roleAssignments = [ + { + name: '902f366b-ba61-4eb6-aa3a-786d317f2dbc' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param skuTier = 'Regional' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -322,7 +403,7 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -415,6 +496,69 @@ module publicIpAddress 'br/public:avm/res/network/public-ip-address:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-address:' + +// Required parameters +param name = 'npiawaf001' +// Non-required parameters +param ddosSettings = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsSettings = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param publicIPAddressVersion = 'IPv4' +param publicIPAllocationMethod = 'Static' +param publicIpPrefixResourceId = '' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param skuTier = 'Regional' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -810,6 +954,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator'` **Required parameters** diff --git a/avm/res/network/public-ip-prefix/README.md b/avm/res/network/public-ip-prefix/README.md index 8b70c24c45..a61f1f8244 100644 --- a/avm/res/network/public-ip-prefix/README.md +++ b/avm/res/network/public-ip-prefix/README.md @@ -57,7 +57,7 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,23 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipmin001' +param prefixLength = 28 +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -141,7 +158,7 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -206,6 +223,55 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipmax001' +param prefixLength = 28 +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'bf62ed65-07be-48e8-b760-2d59795cd282' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -238,7 +304,7 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -270,6 +336,28 @@ module publicIpPrefix 'br/public:avm/res/network/public-ip-prefix:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/public-ip-prefix:' + +// Required parameters +param name = 'npipwaf001' +param prefixLength = 28 +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -371,6 +459,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/public-ip-prefix/main.bicep b/avm/res/network/public-ip-prefix/main.bicep index ce7ae8941a..f53aaf8b6c 100644 --- a/avm/res/network/public-ip-prefix/main.bicep +++ b/avm/res/network/public-ip-prefix/main.bicep @@ -10,7 +10,7 @@ param name string param location string = resourceGroup().location @description('Required. Length of the Public IP Prefix.') -@minValue(28) +@minValue(21) @maxValue(31) param prefixLength int diff --git a/avm/res/network/public-ip-prefix/main.json b/avm/res/network/public-ip-prefix/main.json index f3c6be1419..31a4295388 100644 --- a/avm/res/network/public-ip-prefix/main.json +++ b/avm/res/network/public-ip-prefix/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2074867794511783977" + "version": "0.30.23.60470", + "templateHash": "13346619343009869073" }, "name": "Public IP Prefixes", "description": "This module deploys a Public IP Prefix.", @@ -129,7 +129,7 @@ }, "prefixLength": { "type": "int", - "minValue": 28, + "minValue": 21, "maxValue": 31, "metadata": { "description": "Required. Length of the Public IP Prefix." diff --git a/avm/res/network/route-table/README.md b/avm/res/network/route-table/README.md index c93c63b58a..8e00dd425e 100644 --- a/avm/res/network/route-table/README.md +++ b/avm/res/network/route-table/README.md @@ -56,7 +56,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/route-table:' + +// Required parameters +param name = 'nrtmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -142,7 +158,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -210,6 +226,60 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/route-table:' + +// Required parameters +param name = 'nrtmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'de4b134c-7087-480d-892f-ce6629720d29' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param routes = [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } +] +param tags = { + 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. @@ -255,7 +325,7 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -302,6 +372,41 @@ module routeTable 'br/public:avm/res/network/route-table:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/route-table:' + +// Required parameters +param name = 'nrtwaf001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param routes = [ + { + name: 'default' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopIpAddress: '172.16.0.20' + nextHopType: 'VirtualAppliance' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -395,6 +500,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/service-endpoint-policy/README.md b/avm/res/network/service-endpoint-policy/README.md index bc95b35f17..7bfd1efdeb 100644 --- a/avm/res/network/service-endpoint-policy/README.md +++ b/avm/res/network/service-endpoint-policy/README.md @@ -27,7 +27,8 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/service-endpoint-policy:`. - [Using only defaults](#example-1-using-only-defaults) -- [WAF-aligned](#example-2-waf-aligned) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) ### Example 1: _Using only defaults_ @@ -55,7 +56,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -77,9 +78,25 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

    -### Example 2: _WAF-aligned_ +

    -This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/service-endpoint-policy:' + +// Required parameters +param name = 'nsepmin001' +// Non-required parameters +param location = '' +``` + +
    +

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

    @@ -91,13 +108,32 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy: name: 'serviceEndpointPolicyDeployment' params: { // Required parameters - name: 'nsepwaf001' + name: 'nsepmax001' // Non-required parameters location: '' lock: { kind: 'CanNotDelete' name: 'myCustomLockName' } + roleAssignments: [ + { + name: '36fbc5db-13e9-4bda-9594-1b1cc9db2d6d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + 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' @@ -112,7 +148,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:
    -via JSON Parameter file +via JSON parameters file ```json { @@ -121,7 +157,7 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy: "parameters": { // Required parameters "name": { - "value": "nsepwaf001" + "value": "nsepmax001" }, // Non-required parameters "location": { @@ -133,6 +169,131 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy: "name": "myCustomLockName" } }, + "roleAssignments": { + "value": [ + { + "name": "36fbc5db-13e9-4bda-9594-1b1cc9db2d6d", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "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" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/service-endpoint-policy:' + +// Required parameters +param name = 'nsepmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '36fbc5db-13e9-4bda-9594-1b1cc9db2d6d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:' = { + name: 'serviceEndpointPolicyDeployment' + params: { + // Required parameters + name: 'nsepwaf001' + // Non-required parameters + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "nsepwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -147,6 +308,27 @@ module serviceEndpointPolicy 'br/public:avm/res/network/service-endpoint-policy:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/service-endpoint-policy:' + +// Required parameters +param name = 'nsepwaf001' +// Non-required parameters +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -240,6 +422,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep index ba587c2c4d..6a594af1c8 100644 --- a/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/service-endpoint-policy/tests/e2e/defaults/main.test.bicep @@ -9,14 +9,12 @@ metadata description = 'This instance deploys the module with the minimum set of @description('Optional. The name of the resource group to deploy for testing purposes.') @maxLength(90) -// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' param resourceGroupName string = 'dep-${namePrefix}-network.serviceendpointpolicy-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test param serviceShort string = 'nsepmin' @description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') @@ -42,7 +40,6 @@ module testDeployment '../../../main.bicep' = [ scope: resourceGroup name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { - // You parameters go here name: '${namePrefix}${serviceShort}001' location: resourceLocation } diff --git a/avm/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..7b3d4e8fb0 --- /dev/null +++ b/avm/res/network/service-endpoint-policy/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..43504b4599 --- /dev/null +++ b/avm/res/network/service-endpoint-policy/tests/e2e/max/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.serviceendpointpolicy-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nsepmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: '36fbc5db-13e9-4bda-9594-1b1cc9db2d6d' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + 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/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep index 0076f59669..b2c6f19281 100644 --- a/avm/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/service-endpoint-policy/tests/e2e/waf-aligned/main.test.bicep @@ -9,14 +9,12 @@ metadata description = 'This instance deploys the module in alignment with the b @description('Optional. The name of the resource group to deploy for testing purposes.') @maxLength(90) -// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' param resourceGroupName string = 'dep-${namePrefix}-network.serviceendpointpolicy-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') param resourceLocation string = deployment().location @description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') -// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test param serviceShort string = 'nsepwaf' @description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') @@ -42,13 +40,8 @@ module testDeployment '../../../main.bicep' = [ scope: resourceGroup name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' params: { - // You parameters go here name: '${namePrefix}${serviceShort}001' location: resourceLocation - lock: { - kind: 'CanNotDelete' - name: 'myCustomLockName' - } tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/avm/res/network/trafficmanagerprofile/README.md b/avm/res/network/trafficmanagerprofile/README.md index d7f8192264..707111d930 100644 --- a/avm/res/network/trafficmanagerprofile/README.md +++ b/avm/res/network/trafficmanagerprofile/README.md @@ -57,7 +57,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,22 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/trafficmanagerprofile:' + +// Required parameters +param name = 'ntmpmin001' +// Non-required parameters +param location = 'global' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -148,7 +164,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -223,6 +239,65 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/trafficmanagerprofile:' + +// Required parameters +param name = 'ntmpmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param relativeName = 'ntmpmax001-rn' +param roleAssignments = [ + { + name: '76e7bd82-b689-4072-87be-519bfabf733e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -257,7 +332,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' endpointStatus: 'Enabled' priority: 1 targetResourceId: '' @@ -268,7 +343,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:' endpointStatus: 'Enabled' priority: 2 targetResourceId: '' @@ -301,7 +376,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -334,7 +409,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:", "endpointStatus": "Enabled", "priority": 1, "targetResourceId": "", @@ -345,7 +420,7 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:", "endpointStatus": "Enabled", "priority": 2, "targetResourceId": "", @@ -385,6 +460,74 @@ module trafficmanagerprofile 'br/public:avm/res/network/trafficmanagerprofile:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/trafficmanagerprofile:' + +// Required parameters +param name = 'ntmpwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param endpoints = [ + { + name: 'webApp01Endpoint' + properties: { + endpointLocation: '' + endpointStatus: 'Enabled' + priority: 1 + targetResourceId: '' + weight: 1 + } + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + } + { + name: 'webApp02Endpoint' + properties: { + endpointLocation: '' + endpointStatus: 'Enabled' + priority: 2 + targetResourceId: '' + weight: 1 + } + type: 'Microsoft.Network/trafficManagerProfiles/azureEndpoints' + } +] +param location = 'global' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param monitorConfig = { + path: '/' + port: '443' + protocol: 'https' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -675,6 +818,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'Traffic Manager Contributor'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/trafficmanagerprofile/main.json b/avm/res/network/trafficmanagerprofile/main.json index 275f4d0955..1b1e35e937 100644 --- a/avm/res/network/trafficmanagerprofile/main.json +++ b/avm/res/network/trafficmanagerprofile/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2090813965996228671" + "version": "0.30.23.60470", + "templateHash": "5539048151819308545" }, "name": "Traffic Manager Profiles", "description": "This module deploys a Traffic Manager Profile.", diff --git a/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep index 32d82ac36b..3394fe0e75 100644 --- a/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/trafficmanagerprofile/tests/e2e/waf-aligned/main.test.bicep @@ -11,8 +11,11 @@ metadata description = 'This instance deploys the module in alignment with the b @maxLength(90) param resourceGroupName string = 'dep-${namePrefix}-network.trafficmanagerprofiles-${serviceShort}-rg' -@description('Optional. The location to deploy resources to.') -param resourceLocation string = deployment().location +#disable-next-line no-hardcoded-location +var enforcedLocation01 = 'uksouth' + +#disable-next-line no-hardcoded-location +var enforcedLocation02 = 'ukwest' @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 = 'ntmpwaf' @@ -28,21 +31,21 @@ param namePrefix string = '#_namePrefix_#' // ================= resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { name: resourceGroupName - location: resourceLocation + location: enforcedLocation01 } module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + name: '${uniqueString(deployment().name, enforcedLocation01)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' - location: resourceLocation + location: enforcedLocation01 serverFarmName01: 'dep-${namePrefix}-sf-${serviceShort}01' serverFarmName02: 'dep-${namePrefix}-sf-${serviceShort}02' webApp01Name: 'dep-${namePrefix}-wa-${serviceShort}01' webApp02Name: 'dep-${namePrefix}-wa-${serviceShort}02' - location01: 'eastus' - location02: 'westus' + location01: enforcedLocation01 + location02: enforcedLocation02 } } @@ -50,13 +53,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, enforcedLocation01)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: resourceLocation + location: enforcedLocation01 } } @@ -67,7 +70,7 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t module testDeployment '../../../main.bicep' = [ for iteration in ['init', 'idem']: { scope: resourceGroup - name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, enforcedLocation01)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' location: 'global' @@ -107,7 +110,7 @@ module testDeployment '../../../main.bicep' = [ targetResourceId: nestedDependencies.outputs.webApp01ResourceId weight: 1 priority: 1 - endpointLocation: 'eastus' + endpointLocation: '${enforcedLocation01}' endpointStatus: 'Enabled' } } @@ -118,7 +121,7 @@ module testDeployment '../../../main.bicep' = [ targetResourceId: nestedDependencies.outputs.webApp02ResourceId weight: 1 priority: 2 - endpointLocation: 'westus' + endpointLocation: '${enforcedLocation02}' endpointStatus: 'Enabled' } } diff --git a/avm/res/network/virtual-hub/README.md b/avm/res/network/virtual-hub/README.md index ba68607e76..33a3d5861a 100644 --- a/avm/res/network/virtual-hub/README.md +++ b/avm/res/network/virtual-hub/README.md @@ -62,7 +62,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -90,6 +90,24 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.0.0.0/16' +param name = 'nvhmin' +param virtualWanId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -153,7 +171,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +242,59 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.1.0.0/16' +param name = 'nvhmax' +param virtualWanId = '' +// Non-required parameters +param hubRouteTables = [ + { + name: 'routeTable1' + } +] +param hubVirtualNetworkConnections = [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: { + associatedRouteTable: { + id: '' + } + propagatedRouteTables: { + ids: [ + { + id: '' + } + ] + labels: [ + 'none' + ] + } + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using Routing Intent_ This instance deploys the module the Virtual WAN hub with Routing Intent enabled; requires an existing Virtual Hub, as well the firewall Resource ID. @@ -273,7 +344,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -338,6 +409,45 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.10.0.0/23' +param name = 'nvhrtint' +param virtualWanId = '' +// Non-required parameters +param azureFirewallResourceId = '' +param hubRouteTables = [] +param hubRoutingPreference = 'ASPath' +param hubVirtualNetworkConnections = [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: {} + } +] +param internetToFirewall = false +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateToFirewall = true +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -401,7 +511,7 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -472,6 +582,59 @@ module virtualHub 'br/public:avm/res/network/virtual-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-hub:' + +// Required parameters +param addressPrefix = '10.1.0.0/16' +param name = 'nvhwaf' +param virtualWanId = '' +// Non-required parameters +param hubRouteTables = [ + { + name: 'routeTable1' + } +] +param hubVirtualNetworkConnections = [ + { + name: 'connection1' + remoteVirtualNetworkId: '' + routingConfiguration: { + associatedRouteTable: { + id: '' + } + propagatedRouteTables: { + ids: [ + { + id: '' + } + ] + labels: [ + 'none' + ] + } + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/network/virtual-network-gateway/README.md b/avm/res/network/virtual-network-gateway/README.md index 36648bf55a..290070237e 100644 --- a/avm/res/network/virtual-network-gateway/README.md +++ b/avm/res/network/virtual-network-gateway/README.md @@ -31,12 +31,17 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/virtual-network-gateway:`. - [AAD-VPN](#example-1-aad-vpn) -- [Using only defaults](#example-2-using-only-defaults) -- [ExpressRoute](#example-3-expressroute) -- [Using large parameter set](#example-4-using-large-parameter-set) -- [Using SKU without Availability Zones](#example-5-using-sku-without-availability-zones) -- [VPN](#example-6-vpn) -- [WAF-aligned](#example-7-waf-aligned) +- [VPN Active Active with BGP settings](#example-2-vpn-active-active-with-bgp-settings) +- [VPN Active Active with BGP settings](#example-3-vpn-active-active-with-bgp-settings) +- [VPN Active Active without BGP settings](#example-4-vpn-active-active-without-bgp-settings) +- [VPN Active Passive with BGP settings](#example-5-vpn-active-passive-with-bgp-settings) +- [VPN Active Passive without BGP settings](#example-6-vpn-active-passive-without-bgp-settings) +- [Using only defaults](#example-7-using-only-defaults) +- [ExpressRoute](#example-8-expressroute) +- [Using large parameter set](#example-9-using-large-parameter-set) +- [Using SKU without Availability Zones](#example-10-using-sku-without-availability-zones) +- [VPN](#example-11-vpn) +- [WAF-aligned](#example-12-waf-aligned) ### Example 1: _AAD-VPN_ @@ -52,14 +57,15 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } gatewayType: 'Vpn' - name: 'nvngavpn001' - skuName: 'VpnGw2AZ' + name: 'nvgavpn001' vNetResourceId: '' // Non-required parameters - activeActive: false domainNameLabel: [ - 'dm-nvngavpn' + 'dm-nvgavpn' ] location: '' publicIpZones: [ @@ -67,6 +73,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnClientAadConfiguration: { aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' aadIssuer: '' @@ -88,7 +95,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -96,25 +103,24 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, "name": { - "value": "nvngavpn001" - }, - "skuName": { - "value": "VpnGw2AZ" + "value": "nvgavpn001" }, "vNetResourceId": { "value": "" }, // Non-required parameters - "activeActive": { - "value": false - }, "domainNameLabel": { "value": [ - "dm-nvngavpn" + "dm-nvgavpn" ] }, "location": { @@ -127,6 +133,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnClientAadConfiguration": { "value": { "aadAudience": "41b23e61-6c1e-4545-b367-cd054e0ed4b4", @@ -150,9 +159,51 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -### Example 2: _Using only defaults_ +

    + +via Bicep parameters file -This instance deploys the module with the minimum set of required parameters. +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgavpn001' +param vNetResourceId = '' +// Non-required parameters +param domainNameLabel = [ + 'dm-nvgavpn' +] +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnClientAadConfiguration = { + aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4' + aadIssuer: '' + aadTenant: '' + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnClientProtocols: [ + 'OpenVPN' + ] +} +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 2: _VPN Active Active with BGP settings_ + +This instance deploys the module with the VPN Active Active with BGP settings.

    @@ -164,17 +215,30 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activeActiveBgp' + } gatewayType: 'Vpn' - name: 'nvgmin001' - skuName: 'VpnGw2AZ' + name: 'nvgaab001' vNetResourceId: '' // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaab' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' location: '' publicIpZones: [ 1 2 3 ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' } } ``` @@ -184,7 +248,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:
    -via JSON Parameter file +via JSON parameters file ```json { @@ -192,19 +256,210 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveBgp" + } + }, "gatewayType": { "value": "Vpn" }, "name": { - "value": "nvgmin001" + "value": "nvgaab001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaab" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] }, "skuName": { "value": "VpnGw2AZ" }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgaab001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaab' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 3: _VPN Active Active with BGP settings_ + +This instance deploys the module with the VPN Active Active with APIPA BGP settings. + + +

    + +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + } + gatewayType: 'Vpn' + name: 'nvgaaa001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgaaa' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgaaa001" + }, "vNetResourceId": { "value": "" }, // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaaa" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, "location": { "value": "" }, @@ -214,6 +469,15 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2, 3 ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" } } } @@ -222,9 +486,54 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -### Example 3: _ExpressRoute_ +

    -This instance deploys the module with the ExpressRoute set of required parameters. +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgaaa001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaaa' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 4: _VPN Active Active without BGP settings_ + +This instance deploys the module with the VPN Active Active without BGP settings.

    @@ -236,21 +545,30 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters - gatewayType: 'ExpressRoute' - name: 'nvger001' - skuName: 'ErGw1AZ' + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgaa001' vNetResourceId: '' // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true domainNameLabel: [ - 'dm-nvger' + 'dm-nvgaa' ] - gatewayPipName: 'pip-nvger' + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' location: '' publicIpZones: [ 1 2 3 ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' } } ``` @@ -260,7 +578,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:
    -via JSON Parameter file +via JSON parameters file ```json { @@ -268,14 +586,591 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, "gatewayType": { - "value": "ExpressRoute" + "value": "Vpn" }, "name": { - "value": "nvger001" + "value": "nvgaa001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgaa" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] }, "skuName": { - "value": "ErGw1AZ" + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgaa001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgaa' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 5: _VPN Active Passive with BGP settings_ + +This instance deploys the module with the VPN Active Passive with APIPA BGP settings. + + +

    + +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + asn: 65815 + clusterMode: 'activePassiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + } + gatewayType: 'Vpn' + name: 'nvgapb001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgapb' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "asn": 65815, + "clusterMode": "activePassiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ] + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgapb001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgapb" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + asn: 65815 + clusterMode: 'activePassiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgapb001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgapb' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 6: _VPN Active Passive without BGP settings_ + +This instance deploys the module with the VPN Active Passive without BGP settings. + + +

    + +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgap001' + vNetResourceId: '' + // Non-required parameters + allowRemoteVnetTraffic: true + disableIPSecReplayProtection: true + domainNameLabel: [ + 'dm-nvgap' + ] + enableBgpRouteTranslationForNat: true + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: '' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + vpnGatewayGeneration: 'Generation2' + vpnType: 'RouteBased' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgap001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "allowRemoteVnetTraffic": { + "value": true + }, + "disableIPSecReplayProtection": { + "value": true + }, + "domainNameLabel": { + "value": [ + "dm-nvgap" + ] + }, + "enableBgpRouteTranslationForNat": { + "value": true + }, + "enablePrivateIpAddress": { + "value": true + }, + "gatewayDefaultSiteLocalNetworkGatewayId": { + "value": "" + }, + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + }, + "vpnGatewayGeneration": { + "value": "Generation2" + }, + "vpnType": { + "value": "RouteBased" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgap001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgap' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 7: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + gatewayType: 'Vpn' + name: 'nvgmin001' + vNetResourceId: '' + // Non-required parameters + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'VpnGw2AZ' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, + "gatewayType": { + "value": "Vpn" + }, + "name": { + "value": "nvgmin001" + }, + "vNetResourceId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + }, + "publicIpZones": { + "value": [ + 1, + 2, + 3 + ] + }, + "skuName": { + "value": "VpnGw2AZ" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgmin001' +param vNetResourceId = '' +// Non-required parameters +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +``` + +
    +

    + +### Example 8: _ExpressRoute_ + +This instance deploys the module with the ExpressRoute set of required parameters. + + +

    + +via Bicep module + +```bicep +module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:' = { + name: 'virtualNetworkGatewayDeployment' + params: { + // Required parameters + clusterSettings: { + clusterMode: 'activePassiveBgp' + } + gatewayType: 'ExpressRoute' + name: 'nvger001' + vNetResourceId: '' + // Non-required parameters + domainNameLabel: [ + 'dm-nvger' + ] + gatewayPipName: 'pip-nvger' + location: '' + publicIpZones: [ + 1 + 2 + 3 + ] + skuName: 'ErGw1AZ' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveBgp" + } + }, + "gatewayType": { + "value": "ExpressRoute" + }, + "name": { + "value": "nvger001" }, "vNetResourceId": { "value": "" @@ -298,6 +1193,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2, 3 ] + }, + "skuName": { + "value": "ErGw1AZ" } } } @@ -306,7 +1204,38 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -### Example 4: _Using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveBgp' +} +param gatewayType = 'ExpressRoute' +param name = 'nvger001' +param vNetResourceId = '' +// Non-required parameters +param domainNameLabel = [ + 'dm-nvger' +] +param gatewayPipName = 'pip-nvger' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'ErGw1AZ' +``` + +
    +

    + +### Example 9: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -320,12 +1249,22 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + activeGatewayPipName: 'nvgmax001-pip2' + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + } gatewayType: 'Vpn' name: 'nvgmax001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: true allowRemoteVnetTraffic: true diagnosticSettings: [ { @@ -411,6 +1350,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: roleDefinitionIdOrName: '' } ] + skuName: 'VpnGw2AZ' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -427,7 +1367,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -435,22 +1375,30 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "activeGatewayPipName": "nvgmax001-pip2", + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ] + } + }, "gatewayType": { "value": "Vpn" }, "name": { "value": "nvgmax001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, // Non-required parameters - "activeActive": { - "value": true - }, "allowRemoteVnetTraffic": { "value": true }, @@ -560,6 +1508,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: } ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -580,7 +1531,129 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -### Example 5: _Using SKU without Availability Zones_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + activeGatewayPipName: 'nvgmax001-pip2' + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgmax001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgmax' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + mode: 'IngressSnat' + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + } + { + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + mode: 'EgressSnat' + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + } +] +param publicIpZones = [ + 1 + 2 + 3 +] +param roleAssignments = [ + { + name: 'db30550e-70b7-4dbe-901e-e9363b69c05f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'VpnGw2AZ' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 10: _Using SKU without Availability Zones_ This instance deploys the module with a SKU that does not support Availability Zones. @@ -594,12 +1667,16 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } gatewayType: 'Vpn' name: 'nvgnaz001' - skuName: 'VpnGw1' vNetResourceId: '' // Non-required parameters location: '' + publicIpZones: [] + skuName: 'VpnGw1' } } ``` @@ -609,7 +1686,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -617,21 +1694,29 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activePassiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, "name": { "value": "nvgnaz001" }, - "skuName": { - "value": "VpnGw1" - }, "vNetResourceId": { "value": "" }, // Non-required parameters "location": { "value": "" + }, + "publicIpZones": { + "value": [] + }, + "skuName": { + "value": "VpnGw1" } } } @@ -640,7 +1725,30 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -### Example 6: _VPN_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activePassiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgnaz001' +param vNetResourceId = '' +// Non-required parameters +param location = '' +param publicIpZones = [] +param skuName = 'VpnGw1' +``` + +
    +

    + +### Example 11: _VPN_ This instance deploys the module with the VPN set of required parameters. @@ -654,12 +1762,13 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } gatewayType: 'Vpn' name: 'nvgvpn001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: true allowRemoteVnetTraffic: true disableIPSecReplayProtection: true domainNameLabel: [ @@ -674,6 +1783,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' vpnGatewayGeneration: 'Generation2' vpnType: 'RouteBased' } @@ -685,7 +1795,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -693,22 +1803,21 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "clusterMode": "activeActiveNoBgp" + } + }, "gatewayType": { "value": "Vpn" }, "name": { "value": "nvgvpn001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, // Non-required parameters - "activeActive": { - "value": true - }, "allowRemoteVnetTraffic": { "value": true }, @@ -739,6 +1848,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "vpnGatewayGeneration": { "value": "Generation2" }, @@ -752,7 +1864,44 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -### Example 7: _WAF-aligned_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + clusterMode: 'activeActiveNoBgp' +} +param gatewayType = 'Vpn' +param name = 'nvgvpn001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgvpn' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + +### Example 12: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -766,12 +1915,22 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: name: 'virtualNetworkGatewayDeployment' params: { // Required parameters + clusterSettings: { + asn: 65515 + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] + } gatewayType: 'Vpn' name: 'nvgmwaf001' - skuName: 'VpnGw2AZ' vNetResourceId: '' // Non-required parameters - activeActive: true allowRemoteVnetTraffic: true diagnosticSettings: [ { @@ -838,6 +1997,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 2 3 ] + skuName: 'VpnGw2AZ' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -854,7 +2014,7 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -862,22 +2022,30 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: "contentVersion": "1.0.0.0", "parameters": { // Required parameters + "clusterSettings": { + "value": { + "asn": 65515, + "clusterMode": "activeActiveBgp", + "customBgpIpAddresses": [ + "169.254.21.4", + "169.254.21.5" + ], + "secondCustomBgpIpAddresses": [ + "169.254.22.4", + "169.254.22.5" + ] + } + }, "gatewayType": { "value": "Vpn" }, "name": { "value": "nvgmwaf001" }, - "skuName": { - "value": "VpnGw2AZ" - }, "vNetResourceId": { "value": "" }, // Non-required parameters - "activeActive": { - "value": true - }, "allowRemoteVnetTraffic": { "value": true }, @@ -966,6 +2134,9 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: 3 ] }, + "skuName": { + "value": "VpnGw2AZ" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -986,32 +2157,131 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network-gateway:' + +// Required parameters +param clusterSettings = { + asn: 65515 + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: [ + '169.254.21.4' + '169.254.21.5' + ] + secondCustomBgpIpAddresses: [ + '169.254.22.4' + '169.254.22.5' + ] +} +param gatewayType = 'Vpn' +param name = 'nvgmwaf001' +param vNetResourceId = '' +// Non-required parameters +param allowRemoteVnetTraffic = true +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableIPSecReplayProtection = true +param domainNameLabel = [ + 'dm-nvgmwaf' +] +param enableBgpRouteTranslationForNat = true +param enablePrivateIpAddress = true +param gatewayDefaultSiteLocalNetworkGatewayId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.0.0/24' + portRange: '100' + } + ] + internalMappings: [ + { + addressSpace: '10.100.0.0/24' + portRange: '100' + } + ] + mode: 'IngressSnat' + name: 'nat-rule-1-static-IngressSnat' + type: 'Static' + } + { + externalMappings: [ + { + addressSpace: '10.200.0.0/26' + } + ] + internalMappings: [ + { + addressSpace: '172.16.0.0/26' + } + ] + mode: 'EgressSnat' + name: 'nat-rule-2-dynamic-EgressSnat' + type: 'Static' + } +] +param publicIpZones = [ + 1 + 2 + 3 +] +param skuName = 'VpnGw2AZ' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnGatewayGeneration = 'Generation2' +param vpnType = 'RouteBased' +``` + +
    +

    + ## Parameters **Required parameters** | Parameter | Type | Description | | :-- | :-- | :-- | +| [`clusterSettings`](#parameter-clustersettings) | object | Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP. | | [`gatewayType`](#parameter-gatewaytype) | string | Specifies the gateway type. E.g. VPN, ExpressRoute. | | [`name`](#parameter-name) | string | Specifies the Virtual Network Gateway name. | -| [`skuName`](#parameter-skuname) | string | The SKU of the Gateway. | | [`vNetResourceId`](#parameter-vnetresourceid) | string | Virtual Network resource ID. | **Optional parameters** | Parameter | Type | Description | | :-- | :-- | :-- | -| [`activeActive`](#parameter-activeactive) | bool | Value to specify if the Gateway should be deployed in active-active or active-passive configuration. | -| [`activeGatewayPipName`](#parameter-activegatewaypipname) | string | Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip' suffix will be appended to the gateway's name. | | [`allowRemoteVnetTraffic`](#parameter-allowremotevnettraffic) | bool | Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN. | | [`allowVirtualWanTraffic`](#parameter-allowvirtualwantraffic) | bool | Configures this gateway to accept traffic from remote Virtual WAN networks. | -| [`asn`](#parameter-asn) | int | ASN value. | | [`clientRevokedCertThumbprint`](#parameter-clientrevokedcertthumbprint) | string | Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet. | | [`clientRootCertData`](#parameter-clientrootcertdata) | string | Client root certificate data used to authenticate VPN clients. Cannot be configured if vpnClientAadConfiguration is provided. | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`disableIPSecReplayProtection`](#parameter-disableipsecreplayprotection) | bool | disableIPSecReplayProtection flag. Used for VPN Gateways. | | [`domainNameLabel`](#parameter-domainnamelabel) | array | DNS name(s) of the Public IP resource(s). If you enabled active-active configuration, you need to provide 2 DNS names, if you want to use this feature. A region specific suffix will be appended to it, e.g.: your-DNS-name.westeurope.cloudapp.azure.com. | -| [`enableBgp`](#parameter-enablebgp) | bool | Value to specify if BGP is enabled or not. | | [`enableBgpRouteTranslationForNat`](#parameter-enablebgproutetranslationfornat) | bool | EnableBgpRouteTranslationForNat flag. Can only be used when "natRules" are enabled on the Virtual Network Gateway. | | [`enableDnsForwarding`](#parameter-enablednsforwarding) | bool | Whether DNS forwarding is enabled or not and is only supported for Express Route Gateways. The DNS forwarding feature flag must be enabled on the current subscription. | | [`enablePrivateIpAddress`](#parameter-enableprivateipaddress) | bool | Whether private IP needs to be enabled on this gateway for connections or not. Used for configuring a Site-to-Site VPN connection over ExpressRoute private peering. | @@ -1025,12 +2295,20 @@ module virtualNetworkGateway 'br/public:avm/res/network/virtual-network-gateway: | [`publicIPPrefixResourceId`](#parameter-publicipprefixresourceid) | string | Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. | | [`publicIpZones`](#parameter-publicipzones) | array | Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuName`](#parameter-skuname) | string | The SKU of the Gateway. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`vpnClientAadConfiguration`](#parameter-vpnclientaadconfiguration) | object | Configuration for AAD Authentication for P2S Tunnel Type, Cannot be configured if clientRootCertData is provided. | | [`vpnClientAddressPoolPrefix`](#parameter-vpnclientaddresspoolprefix) | string | The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network. | | [`vpnGatewayGeneration`](#parameter-vpngatewaygeneration) | string | The generation for this VirtualNetworkGateway. Must be None if virtualNetworkGatewayType is not VPN. | | [`vpnType`](#parameter-vpntype) | string | Specifies the VPN type. | +### Parameter: `clusterSettings` + +Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP. + +- Required: Yes +- Type: object + ### Parameter: `gatewayType` Specifies the gateway type. E.g. VPN, ExpressRoute. @@ -1052,35 +2330,6 @@ Specifies the Virtual Network Gateway name. - Required: Yes - Type: string -### Parameter: `skuName` - -The SKU of the Gateway. - -- Required: Yes -- Type: string -- Allowed: - ```Bicep - [ - 'Basic' - 'ErGw1AZ' - 'ErGw2AZ' - 'ErGw3AZ' - 'HighPerformance' - 'Standard' - 'UltraPerformance' - 'VpnGw1' - 'VpnGw1AZ' - 'VpnGw2' - 'VpnGw2AZ' - 'VpnGw3' - 'VpnGw3AZ' - 'VpnGw4' - 'VpnGw4AZ' - 'VpnGw5' - 'VpnGw5AZ' - ] - ``` - ### Parameter: `vNetResourceId` Virtual Network resource ID. @@ -1088,22 +2337,6 @@ Virtual Network resource ID. - Required: Yes - Type: string -### Parameter: `activeActive` - -Value to specify if the Gateway should be deployed in active-active or active-passive configuration. - -- Required: No -- Type: bool -- Default: `True` - -### Parameter: `activeGatewayPipName` - -Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip' suffix will be appended to the gateway's name. - -- Required: No -- Type: string -- Default: `[format('{0}-pip2', parameters('name'))]` - ### Parameter: `allowRemoteVnetTraffic` Configure this gateway to accept traffic from other Azure Virtual Networks. This configuration does not support connectivity to Azure Virtual WAN. @@ -1120,14 +2353,6 @@ Configures this gateway to accept traffic from remote Virtual WAN networks. - Type: bool - Default: `False` -### Parameter: `asn` - -ASN value. - -- Required: No -- Type: int -- Default: `65815` - ### Parameter: `clientRevokedCertThumbprint` Thumbprint of the revoked certificate. This would revoke VPN client certificates matching this thumbprint from connecting to the VNet. @@ -1306,14 +2531,6 @@ DNS name(s) of the Public IP resource(s). If you enabled active-active configura - Type: array - Default: `[]` -### Parameter: `enableBgp` - -Value to specify if BGP is enabled or not. - -- Required: No -- Type: bool -- Default: `True` - ### Parameter: `enableBgpRouteTranslationForNat` EnableBgpRouteTranslationForNat flag. Can only be used when "natRules" are enabled on the Virtual Network Gateway. @@ -1574,7 +2791,14 @@ Specifies the zones of the Public IP address. Basic IP SKU does not support Avai - Required: No - Type: array -- Default: `[]` +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` ### Parameter: `roleAssignments` @@ -1582,6 +2806,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1673,6 +2904,36 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `skuName` + +The SKU of the Gateway. + +- Required: No +- Type: string +- Default: `[if(equals(parameters('gatewayType'), 'VPN'), 'VpnGw1AZ', 'ErGw1AZ')]` +- Allowed: + ```Bicep + [ + 'Basic' + 'ErGw1AZ' + 'ErGw2AZ' + 'ErGw3AZ' + 'HighPerformance' + 'Standard' + 'UltraPerformance' + 'VpnGw1' + 'VpnGw1AZ' + 'VpnGw2' + 'VpnGw2AZ' + 'VpnGw3' + 'VpnGw3AZ' + 'VpnGw4' + 'VpnGw4AZ' + 'VpnGw5' + 'VpnGw5AZ' + ] + ``` + ### Parameter: `tags` Tags of the resource. diff --git a/avm/res/network/virtual-network-gateway/main.bicep b/avm/res/network/virtual-network-gateway/main.bicep index 6b73abca5d..4cf0d87c15 100644 --- a/avm/res/network/virtual-network-gateway/main.bicep +++ b/avm/res/network/virtual-network-gateway/main.bicep @@ -11,14 +11,15 @@ param location string = resourceGroup().location @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway. If it\'s not provided, a \'-pip\' suffix will be appended to the gateway\'s name.') param gatewayPipName string = '${name}-pip1' -@description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip\' suffix will be appended to the gateway\'s name.') -param activeGatewayPipName string = '${name}-pip2' - @description('Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix.') param publicIPPrefixResourceId string = '' @description('Optional. Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones.') -param publicIpZones array = [] +param publicIpZones array = [ + 1 + 2 + 3 +] @description('Optional. DNS name(s) of the Public IP resource(s). If you enabled active-active configuration, you need to provide 2 DNS names, if you want to use this feature. A region specific suffix will be appended to it, e.g.: your-DNS-name.westeurope.cloudapp.azure.com.') param domainNameLabel array = [] @@ -38,7 +39,7 @@ param gatewayType string ]) param vpnGatewayGeneration string = 'None' -@description('Required. The SKU of the Gateway.') +@description('Optional. The SKU of the Gateway.') @allowed([ 'Basic' 'VpnGw1' @@ -58,7 +59,7 @@ param vpnGatewayGeneration string = 'None' 'ErGw2AZ' 'ErGw3AZ' ]) -param skuName string +param skuName string = (gatewayType == 'VPN') ? 'VpnGw1AZ' : 'ErGw1AZ' @description('Optional. Specifies the VPN type.') @allowed([ @@ -70,14 +71,8 @@ param vpnType string = 'RouteBased' @description('Required. Virtual Network resource ID.') param vNetResourceId string -@description('Optional. Value to specify if the Gateway should be deployed in active-active or active-passive configuration.') -param activeActive bool = true - -@description('Optional. Value to specify if BGP is enabled or not.') -param enableBgp bool = true - -@description('Optional. ASN value.') -param asn int = 65815 +@description('Required. Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP.') +param clusterSettings clusterSettingType @description('Optional. The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network.') param vpnClientAddressPoolPrefix string = '' @@ -140,25 +135,52 @@ param vpnClientAadConfiguration object = {} // Other Variables var gatewayPipAllocationMethod = skuName == 'Basic' ? 'Dynamic' : 'Static' -var isActiveActiveValid = gatewayType != 'ExpressRoute' ? activeActive : false -var virtualGatewayPipNameVar = isActiveActiveValid +var isExpressRoute = gatewayType == 'ExpressRoute' + +var vpnTypeVar = !isExpressRoute ? vpnType : 'PolicyBased' + +var isBgp = (clusterSettings.clusterMode == 'activeActiveBgp' || clusterSettings.clusterMode == 'activePassiveBgp') && !isExpressRoute + +var isActiveActive = (clusterSettings.clusterMode == 'activeActiveNoBgp' || clusterSettings.clusterMode == 'activeActiveBgp') && !isExpressRoute + +var activeGatewayPipNameVar = isActiveActive ? (clusterSettings.?activeGatewayPipName ?? '${name}-pip2') : null + +var virtualGatewayPipNameVar = isActiveActive ? [ gatewayPipName - activeGatewayPipName + activeGatewayPipNameVar ] : [ gatewayPipName ] -var vpnTypeVar = gatewayType != 'ExpressRoute' ? vpnType : 'PolicyBased' - -var isBgpValid = gatewayType != 'ExpressRoute' ? enableBgp : false -var bgpSettings = { - asn: asn -} +// Potential BGP configurations (active-active vs active-passive) +var bgpSettingsVar = isActiveActive + ? { + asn: clusterSettings.?asn ?? 65515 + bgpPeeringAddresses: [ + { + customBgpIpAddresses: clusterSettings.?customBgpIpAddresses + ipconfigurationId: '${az.resourceId('Microsoft.Network/virtualNetworkGateways', name)}/ipConfigurations/vNetGatewayConfig1' + } + { + customBgpIpAddresses: clusterSettings.?secondCustomBgpIpAddresses + ipconfigurationId: '${az.resourceId('Microsoft.Network/virtualNetworkGateways', name)}/ipConfigurations/vNetGatewayConfig2' + } + ] + } + : { + asn: clusterSettings.?asn ?? 65515 + bgpPeeringAddresses: [ + { + customBgpIpAddresses: clusterSettings.?customBgpIpAddresses + ipconfigurationId: '${az.resourceId('Microsoft.Network/virtualNetworkGateways', name)}/ipConfigurations/vNetGatewayConfig1' + } + ] + } -// Potential configurations (active-active vs active-passive) -var ipConfiguration = isActiveActiveValid +// Potential IP configurations (active-active vs active-passive) +var ipConfiguration = isActiveActive ? [ { properties: { @@ -179,8 +201,8 @@ var ipConfiguration = isActiveActiveValid id: '${vNetResourceId}/subnets/GatewaySubnet' } publicIPAddress: { - id: isActiveActiveValid - ? az.resourceId('Microsoft.Network/publicIPAddresses', activeGatewayPipName) + id: isActiveActive + ? az.resourceId('Microsoft.Network/publicIPAddresses', activeGatewayPipNameVar) : az.resourceId('Microsoft.Network/publicIPAddresses', gatewayPipName) } } @@ -331,13 +353,13 @@ resource virtualNetworkGateway 'Microsoft.Network/virtualNetworkGateways@2023-04 tags: tags properties: { ipConfigurations: ipConfiguration - activeActive: isActiveActiveValid + activeActive: isActiveActive allowRemoteVnetTraffic: allowRemoteVnetTraffic allowVirtualWanTraffic: allowVirtualWanTraffic - enableBgp: isBgpValid - bgpSettings: isBgpValid ? bgpSettings : null + enableBgp: isBgp + bgpSettings: isBgp ? bgpSettingsVar : null disableIPSecReplayProtection: disableIPSecReplayProtection - enableDnsForwarding: gatewayType == 'ExpressRoute' ? enableDnsForwarding : null + enableDnsForwarding: !isExpressRoute ? enableDnsForwarding : null enablePrivateIpAddress: enablePrivateIpAddress enableBgpRouteTranslationForNat: enableBgpRouteTranslationForNat gatewayType: gatewayType @@ -365,11 +387,11 @@ module virtualNetworkGateway_natRules 'nat-rule/main.bicep' = [ params: { name: natRule.name virtualNetworkGatewayName: virtualNetworkGateway.name - externalMappings: contains(natRule, 'externalMappings') ? natRule.externalMappings : [] - internalMappings: contains(natRule, 'internalMappings') ? natRule.internalMappings : [] - ipConfigurationId: contains(natRule, 'ipConfigurationId') ? natRule.ipConfigurationId : '' - mode: contains(natRule, 'mode') ? natRule.mode : '' - type: contains(natRule, 'type') ? natRule.type : '' + externalMappings: natRule.?externalMappings ?? [] + internalMappings: natRule.?internalMappings ?? [] + ipConfigurationId: natRule.?ipConfigurationId ?? '' + mode: natRule.?mode ?? '' + type: natRule.?type ?? '' } } ] @@ -533,3 +555,47 @@ 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 activePassiveNoBgpType = { + clusterMode: 'activePassiveNoBgp' +} + +type activeActiveNoBgpType = { + clusterMode: 'activeActiveNoBgp' + + @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') + activeGatewayPipName: string? +} + +type activePassiveBgpType = { + clusterMode: 'activePassiveBgp' + + @description('Optional. The Autonomous System Number value. If it\'s not provided, a default \'65515\' value will be assigned to the ASN.') + @minValue(0) + @maxValue(4294967295) + asn: int? + + @description('Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration.') + customBgpIpAddresses: string[]? +} + +type activeActiveBgpType = { + clusterMode: 'activeActiveBgp' + + @description('Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it\'s not provided, a \'-pip2\' suffix will be appended to the gateway\'s name.') + activeGatewayPipName: string? + + @description('Optional. The Autonomous System Number value. If it\'s not provided, a default \'65515\' value will be assigned to the ASN.') + @minValue(0) + @maxValue(4294967295) + asn: int? + + @description('Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration.') + customBgpIpAddresses: string[]? + + @description('Optional. The list of the second custom BGP IP Address (APIPA) peering addresses which belong to IP configuration.') + secondCustomBgpIpAddresses: string[]? +} + +@discriminator('clusterMode') +type clusterSettingType = activeActiveNoBgpType | activeActiveBgpType | activePassiveBgpType | activePassiveNoBgpType diff --git a/avm/res/network/virtual-network-gateway/main.json b/avm/res/network/virtual-network-gateway/main.json index 19876a6210..5badcfef95 100644 --- a/avm/res/network/virtual-network-gateway/main.json +++ b/avm/res/network/virtual-network-gateway/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15596993518588024968" + "version": "0.30.23.60470", + "templateHash": "6347373659148864152" }, "name": "Virtual Network Gateways", "description": "This module deploys a Virtual Network Gateway.", @@ -230,6 +230,132 @@ } }, "nullable": true + }, + "activePassiveNoBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activePassiveNoBgp" + ] + } + } + }, + "activeActiveNoBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activeActiveNoBgp" + ] + }, + "activeGatewayPipName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip2' suffix will be appended to the gateway's name." + } + } + } + }, + "activePassiveBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activePassiveBgp" + ] + }, + "asn": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 4294967295, + "metadata": { + "description": "Optional. The Autonomous System Number value. If it's not provided, a default '65515' value will be assigned to the ASN." + } + }, + "customBgpIpAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration." + } + } + } + }, + "activeActiveBgpType": { + "type": "object", + "properties": { + "clusterMode": { + "type": "string", + "allowedValues": [ + "activeActiveBgp" + ] + }, + "activeGatewayPipName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip2' suffix will be appended to the gateway's name." + } + }, + "asn": { + "type": "int", + "nullable": true, + "minValue": 0, + "maxValue": 4294967295, + "metadata": { + "description": "Optional. The Autonomous System Number value. If it's not provided, a default '65515' value will be assigned to the ASN." + } + }, + "customBgpIpAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of custom BGP IP Address (APIPA) peering addresses which belong to IP configuration." + } + }, + "secondCustomBgpIpAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The list of the second custom BGP IP Address (APIPA) peering addresses which belong to IP configuration." + } + } + } + }, + "clusterSettingType": { + "type": "object", + "discriminator": { + "propertyName": "clusterMode", + "mapping": { + "activeActiveNoBgp": { + "$ref": "#/definitions/activeActiveNoBgpType" + }, + "activeActiveBgp": { + "$ref": "#/definitions/activeActiveBgpType" + }, + "activePassiveBgp": { + "$ref": "#/definitions/activePassiveBgpType" + }, + "activePassiveNoBgp": { + "$ref": "#/definitions/activePassiveNoBgpType" + } + } + } } }, "parameters": { @@ -253,13 +379,6 @@ "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway. If it's not provided, a '-pip' suffix will be appended to the gateway's name." } }, - "activeGatewayPipName": { - "type": "string", - "defaultValue": "[format('{0}-pip2', parameters('name'))]", - "metadata": { - "description": "Optional. Specifies the name of the Public IP used by the Virtual Network Gateway when active-active configuration is required. If it's not provided, a '-pip' suffix will be appended to the gateway's name." - } - }, "publicIPPrefixResourceId": { "type": "string", "defaultValue": "", @@ -269,7 +388,11 @@ }, "publicIpZones": { "type": "array", - "defaultValue": [], + "defaultValue": [ + 1, + 2, + 3 + ], "metadata": { "description": "Optional. Specifies the zones of the Public IP address. Basic IP SKU does not support Availability Zones." } @@ -305,6 +428,7 @@ }, "skuName": { "type": "string", + "defaultValue": "[if(equals(parameters('gatewayType'), 'VPN'), 'VpnGw1AZ', 'ErGw1AZ')]", "allowedValues": [ "Basic", "VpnGw1", @@ -325,7 +449,7 @@ "ErGw3AZ" ], "metadata": { - "description": "Required. The SKU of the Gateway." + "description": "Optional. The SKU of the Gateway." } }, "vpnType": { @@ -345,25 +469,10 @@ "description": "Required. Virtual Network resource ID." } }, - "activeActive": { - "type": "bool", - "defaultValue": true, + "clusterSettings": { + "$ref": "#/definitions/clusterSettingType", "metadata": { - "description": "Optional. Value to specify if the Gateway should be deployed in active-active or active-passive configuration." - } - }, - "enableBgp": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Value to specify if BGP is enabled or not." - } - }, - "asn": { - "type": "int", - "defaultValue": 65815, - "metadata": { - "description": "Optional. ASN value." + "description": "Required. Specifies one of the following four configurations: Active-Active with (clusterMode = activeActiveBgp) or without (clusterMode = activeActiveNoBgp) BGP, Active-Passive with (clusterMode = activePassiveBgp) or without (clusterMode = activePassiveNoBgp) BGP." } }, "vpnClientAddressPoolPrefix": { @@ -498,14 +607,14 @@ } ], "gatewayPipAllocationMethod": "[if(equals(parameters('skuName'), 'Basic'), 'Dynamic', 'Static')]", - "isActiveActiveValid": "[if(not(equals(parameters('gatewayType'), 'ExpressRoute')), parameters('activeActive'), false())]", - "virtualGatewayPipNameVar": "[if(variables('isActiveActiveValid'), createArray(parameters('gatewayPipName'), parameters('activeGatewayPipName')), createArray(parameters('gatewayPipName')))]", - "vpnTypeVar": "[if(not(equals(parameters('gatewayType'), 'ExpressRoute')), parameters('vpnType'), 'PolicyBased')]", - "isBgpValid": "[if(not(equals(parameters('gatewayType'), 'ExpressRoute')), parameters('enableBgp'), false())]", - "bgpSettings": { - "asn": "[parameters('asn')]" - }, - "ipConfiguration": "[if(variables('isActiveActiveValid'), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1'), createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(variables('isActiveActiveValid'), resourceId('Microsoft.Network/publicIPAddresses', parameters('activeGatewayPipName')), resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName'))))), 'name', 'vNetGatewayConfig2')), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1')))]", + "isExpressRoute": "[equals(parameters('gatewayType'), 'ExpressRoute')]", + "vpnTypeVar": "[if(not(variables('isExpressRoute')), parameters('vpnType'), 'PolicyBased')]", + "isBgp": "[and(or(equals(parameters('clusterSettings').clusterMode, 'activeActiveBgp'), equals(parameters('clusterSettings').clusterMode, 'activePassiveBgp')), not(variables('isExpressRoute')))]", + "isActiveActive": "[and(or(equals(parameters('clusterSettings').clusterMode, 'activeActiveNoBgp'), equals(parameters('clusterSettings').clusterMode, 'activeActiveBgp')), not(variables('isExpressRoute')))]", + "activeGatewayPipNameVar": "[if(variables('isActiveActive'), coalesce(tryGet(parameters('clusterSettings'), 'activeGatewayPipName'), format('{0}-pip2', parameters('name'))), null())]", + "virtualGatewayPipNameVar": "[if(variables('isActiveActive'), createArray(parameters('gatewayPipName'), variables('activeGatewayPipNameVar')), createArray(parameters('gatewayPipName')))]", + "bgpSettingsVar": "[if(variables('isActiveActive'), createObject('asn', coalesce(tryGet(parameters('clusterSettings'), 'asn'), 65515), 'bgpPeeringAddresses', createArray(createObject('customBgpIpAddresses', tryGet(parameters('clusterSettings'), 'customBgpIpAddresses'), 'ipconfigurationId', format('{0}/ipConfigurations/vNetGatewayConfig1', resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')))), createObject('customBgpIpAddresses', tryGet(parameters('clusterSettings'), 'secondCustomBgpIpAddresses'), 'ipconfigurationId', format('{0}/ipConfigurations/vNetGatewayConfig2', resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')))))), createObject('asn', coalesce(tryGet(parameters('clusterSettings'), 'asn'), 65515), 'bgpPeeringAddresses', createArray(createObject('customBgpIpAddresses', tryGet(parameters('clusterSettings'), 'customBgpIpAddresses'), 'ipconfigurationId', format('{0}/ipConfigurations/vNetGatewayConfig1', resourceId('Microsoft.Network/virtualNetworkGateways', parameters('name')))))))]", + "ipConfiguration": "[if(variables('isActiveActive'), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1'), createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', if(variables('isActiveActive'), resourceId('Microsoft.Network/publicIPAddresses', variables('activeGatewayPipNameVar')), resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName'))))), 'name', 'vNetGatewayConfig2')), createArray(createObject('properties', createObject('privateIPAllocationMethod', 'Dynamic', 'subnet', createObject('id', format('{0}/subnets/GatewaySubnet', parameters('vNetResourceId'))), 'publicIPAddress', createObject('id', resourceId('Microsoft.Network/publicIPAddresses', parameters('gatewayPipName')))), 'name', 'vNetGatewayConfig1')))]", "vpnClientConfiguration": "[if(not(empty(parameters('clientRootCertData'))), createObject('vpnClientAddressPool', createObject('addressPrefixes', createArray(parameters('vpnClientAddressPoolPrefix'))), 'vpnClientRootCertificates', createArray(createObject('name', 'RootCert1', 'properties', createObject('publicCertData', parameters('clientRootCertData')))), 'vpnClientRevokedCertificates', if(not(empty(parameters('clientRevokedCertThumbprint'))), createArray(createObject('name', 'RevokedCert1', 'properties', createObject('thumbprint', parameters('clientRevokedCertThumbprint')))), null())), if(not(empty(parameters('vpnClientAadConfiguration'))), createObject('vpnClientAddressPool', createObject('addressPrefixes', createArray(parameters('vpnClientAddressPoolPrefix'))), 'aadTenant', parameters('vpnClientAadConfiguration').aadTenant, 'aadAudience', parameters('vpnClientAadConfiguration').aadAudience, 'aadIssuer', parameters('vpnClientAadConfiguration').aadIssuer, 'vpnAuthenticationTypes', parameters('vpnClientAadConfiguration').vpnAuthenticationTypes, 'vpnClientProtocols', parameters('vpnClientAadConfiguration').vpnClientProtocols), null()))]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -545,13 +654,13 @@ "tags": "[parameters('tags')]", "properties": { "ipConfigurations": "[variables('ipConfiguration')]", - "activeActive": "[variables('isActiveActiveValid')]", + "activeActive": "[variables('isActiveActive')]", "allowRemoteVnetTraffic": "[parameters('allowRemoteVnetTraffic')]", "allowVirtualWanTraffic": "[parameters('allowVirtualWanTraffic')]", - "enableBgp": "[variables('isBgpValid')]", - "bgpSettings": "[if(variables('isBgpValid'), variables('bgpSettings'), null())]", + "enableBgp": "[variables('isBgp')]", + "bgpSettings": "[if(variables('isBgp'), variables('bgpSettingsVar'), null())]", "disableIPSecReplayProtection": "[parameters('disableIPSecReplayProtection')]", - "enableDnsForwarding": "[if(equals(parameters('gatewayType'), 'ExpressRoute'), parameters('enableDnsForwarding'), null())]", + "enableDnsForwarding": "[if(not(variables('isExpressRoute')), parameters('enableDnsForwarding'), null())]", "enablePrivateIpAddress": "[parameters('enablePrivateIpAddress')]", "enableBgpRouteTranslationForNat": "[parameters('enableBgpRouteTranslationForNat')]", "gatewayType": "[parameters('gatewayType')]", @@ -1329,11 +1438,21 @@ "virtualNetworkGatewayName": { "value": "[parameters('name')]" }, - "externalMappings": "[if(contains(parameters('natRules')[copyIndex()], 'externalMappings'), createObject('value', parameters('natRules')[copyIndex()].externalMappings), createObject('value', createArray()))]", - "internalMappings": "[if(contains(parameters('natRules')[copyIndex()], 'internalMappings'), createObject('value', parameters('natRules')[copyIndex()].internalMappings), createObject('value', createArray()))]", - "ipConfigurationId": "[if(contains(parameters('natRules')[copyIndex()], 'ipConfigurationId'), createObject('value', parameters('natRules')[copyIndex()].ipConfigurationId), createObject('value', ''))]", - "mode": "[if(contains(parameters('natRules')[copyIndex()], 'mode'), createObject('value', parameters('natRules')[copyIndex()].mode), createObject('value', ''))]", - "type": "[if(contains(parameters('natRules')[copyIndex()], 'type'), createObject('value', parameters('natRules')[copyIndex()].type), createObject('value', ''))]" + "externalMappings": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'externalMappings'), createArray())]" + }, + "internalMappings": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'internalMappings'), createArray())]" + }, + "ipConfigurationId": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'ipConfigurationId'), '')]" + }, + "mode": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'mode'), '')]" + }, + "type": { + "value": "[coalesce(tryGet(parameters('natRules')[copyIndex()], 'type'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1341,8 +1460,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "915174536118171652" + "version": "0.30.23.60470", + "templateHash": "15500017864202979057" }, "name": "VPN Gateway NAT Rules", "description": "This module deploys a Virtual Network Gateway NAT Rule.", diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep index 0b4425a9a0..09457de2bd 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/aadvpn/main.test.bicep @@ -15,7 +15,7 @@ param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgatewa 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 = 'nvngavpn' +param serviceShort string = 'nvgavpn' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' @@ -55,7 +55,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: false + clusterSettings:{ + clusterMode: 'activePassiveNoBgp' + } domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources 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 Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep new file mode 100644 index 0000000000..6270baf598 --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBGP/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active with BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Active with BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaab' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveBgp' + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources 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 Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep new file mode 100644 index 0000000000..16fe844184 --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveBgpAPIPA/main.test.bicep @@ -0,0 +1,85 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active with BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Active with APIPA BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaaa' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + secondCustomBgpIpAddresses: ['169.254.22.4','169.254.22.5'] + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources 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 Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep new file mode 100644 index 0000000000..7d799c5c2c --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activeActiveNoBGP/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Active without BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Active without BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgaa' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activeActiveNoBgp' + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources 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 Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep new file mode 100644 index 0000000000..1aa9da7c34 --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveBGP/main.test.bicep @@ -0,0 +1,85 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Passive with BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Passive with APIPA BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgapb' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode:'activePassiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + asn: 65815 + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep new file mode 100644 index 0000000000..c3aebf111c --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources 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 Local Network Gateway to create.') +param localNetworkGatewayName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource localNetworkGateway 'Microsoft.Network/localNetworkGateways@2023-04-01' = { + name: localNetworkGatewayName + location: location + properties: { + gatewayIpAddress: '100.100.100.100' + localNetworkAddressSpace: { + addressPrefixes: [ + '192.168.0.0/24' + ] + } + } +} + +@description('The resource ID of the created Virtual Network.') +output vnetResourceId string = virtualNetwork.id + +@description('The resource ID of the created Local Network Gateway.') +output localNetworkGatewayResourceId string = localNetworkGateway.id diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep new file mode 100644 index 0000000000..ee3904f4b8 --- /dev/null +++ b/avm/res/network/virtual-network-gateway/tests/e2e/activePassiveNoBGP/main.test.bicep @@ -0,0 +1,83 @@ +targetScope = 'subscription' + +metadata name = 'VPN Active Passive without BGP settings' +metadata description = 'This instance deploys the module with the VPN Active Passive without BGP settings.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.virtualnetworkgateways-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nvgap' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + localNetworkGatewayName: 'dep-${namePrefix}-lng-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + vpnGatewayGeneration: 'Generation2' + skuName: 'VpnGw2AZ' + gatewayType: 'Vpn' + vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode:'activePassiveNoBgp' + } + + domainNameLabel: [ + '${namePrefix}-dm-${serviceShort}' + ] + publicIpZones: [ + 1 + 2 + 3 + ] + vpnType: 'RouteBased' + enablePrivateIpAddress: true + gatewayDefaultSiteLocalNetworkGatewayId: nestedDependencies.outputs.localNetworkGatewayResourceId + disableIPSecReplayProtection: true + allowRemoteVnetTraffic: true + enableBgpRouteTranslationForNat: true + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep index 9e5f80b30c..06f382ecb5 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/defaults/main.test.bicep @@ -62,6 +62,9 @@ module testDeployment '../../../main.bicep' = [ 2 3 ] + clusterSettings: { + clusterMode:'activeActiveNoBgp' + } } dependsOn: [ nestedDependencies diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep index 22b116891b..600e374025 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/expressRoute/main.test.bicep @@ -55,6 +55,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'ErGw1AZ' gatewayType: 'ExpressRoute' vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings:{ + clusterMode: 'activePassiveBgp' + } domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep index 346b380610..b0314fa4dc 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/max/main.test.bicep @@ -72,7 +72,12 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: true + clusterSettings:{ + clusterMode: 'activeActiveBgp' + activeGatewayPipName: '${namePrefix}${serviceShort}001-pip2' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + secondCustomBgpIpAddresses: ['169.254.22.4','169.254.22.5'] + } diagnosticSettings: [ { name: 'customSetting' diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep index 7966ff4a3d..fc3410af52 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/vpn-no-az/main.test.bicep @@ -56,7 +56,11 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' skuName: 'VpnGw1' gatewayType: 'Vpn' + publicIpZones: [] vNetResourceId: nestedDependencies.outputs.vnetResourceId + clusterSettings: { + clusterMode: 'activePassiveNoBgp' + } } dependsOn: [ nestedDependencies diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep index 6ac66acfd1..4258c36c8a 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/vpn/main.test.bicep @@ -57,7 +57,9 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: true + clusterSettings:{ + clusterMode: 'activeActiveNoBgp' + } domainNameLabel: [ '${namePrefix}-dm-${serviceShort}' ] diff --git a/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep index 8a31ac21fc..e0da5f11c5 100644 --- a/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/virtual-network-gateway/tests/e2e/waf-aligned/main.test.bicep @@ -70,7 +70,12 @@ module testDeployment '../../../main.bicep' = [ skuName: 'VpnGw2AZ' gatewayType: 'Vpn' vNetResourceId: nestedDependencies.outputs.vnetResourceId - activeActive: true + clusterSettings: { + clusterMode:'activeActiveBgp' + customBgpIpAddresses: ['169.254.21.4','169.254.21.5'] + secondCustomBgpIpAddresses: ['169.254.22.4','169.254.22.5'] + asn: 65515 + } diagnosticSettings: [ { name: 'customSetting' diff --git a/avm/res/network/virtual-network-gateway/version.json b/avm/res/network/virtual-network-gateway/version.json index 76049e1c4a..13669e6601 100644 --- a/avm/res/network/virtual-network-gateway/version.json +++ b/avm/res/network/virtual-network-gateway/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ] diff --git a/avm/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md index 4b6fa95d30..c61cf59589 100644 --- a/avm/res/network/virtual-network/README.md +++ b/avm/res/network/virtual-network/README.md @@ -65,7 +65,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -92,6 +92,25 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '10.0.0.0/16' +] +param name = 'nvnmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using an IPv6 address space_ This instance deploys the module using an IPv6 address space. @@ -131,7 +150,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -170,6 +189,35 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '10.0.0.0/21' + 'fd00:592b:3014::/64' +] +param name = 'nvnipv6001' +// Non-required parameters +param location = '' +param subnets = [ + { + addressPrefixes: [ + '10.0.0.0/24' + 'fd00:592b:3014::/64' + ] + name: 'ipv6-subnet' + } +] +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -308,7 +356,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -458,6 +506,134 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '' +] +param name = 'nvnmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsServers = [ + '10.0.1.4' + '10.0.1.5' +] +param flowTimeoutInMinutes = 20 +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'f5c27a7b-9b18-4dc1-b002-db3c38e80b64' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param subnets = [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + 'Microsoft.Sql' + 'Microsoft.Storage' + ] + } + { + addressPrefix: '' + delegation: 'Microsoft.Netapp/volumes' + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'az-subnet-x-004' + natGatewayResourceId: '' + networkSecurityGroupResourceId: '' + routeTableResourceId: '' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _Deploying a bi-directional peering_ This instance deploys the module with both an inbound and outbound peering. @@ -520,7 +696,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -586,6 +762,58 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '10.1.0.0/24' +] +param name = 'nvnpeer001' +// Non-required parameters +param location = '' +param peerings = [ + { + allowForwardedTraffic: true + allowGatewayTransit: false + allowVirtualNetworkAccess: true + remotePeeringAllowForwardedTraffic: true + remotePeeringAllowVirtualNetworkAccess: true + remotePeeringEnabled: true + remotePeeringName: 'customName' + remoteVirtualNetworkResourceId: '' + useRemoteGateways: false + } +] +param subnets = [ + { + addressPrefix: '10.1.0.0/26' + name: 'GatewaySubnet' + } + { + addressPrefix: '10.1.0.64/26' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '10.1.0.128/26' + name: 'AzureFirewallSubnet' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -684,7 +912,7 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -790,6 +1018,94 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-network:' + +// Required parameters +param addressPrefixes = [ + '' +] +param name = 'nvnwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsServers = [ + '10.0.1.4' + '10.0.1.5' +] +param flowTimeoutInMinutes = 20 +param location = '' +param subnets = [ + { + addressPrefix: '' + name: 'GatewaySubnet' + } + { + addressPrefix: '' + name: 'az-subnet-x-001' + networkSecurityGroupResourceId: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + routeTableResourceId: '' + serviceEndpoints: [ + 'Microsoft.Sql' + 'Microsoft.Storage' + ] + } + { + addressPrefix: '' + delegation: 'Microsoft.Netapp/volumes' + name: 'az-subnet-x-002' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'az-subnet-x-003' + networkSecurityGroupResourceId: '' + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + addressPrefix: '' + name: 'AzureBastionSubnet' + networkSecurityGroupResourceId: '' + } + { + addressPrefix: '' + name: 'AzureFirewallSubnet' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1195,6 +1511,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -1415,6 +1738,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/virtual-network/subnet/README.md b/avm/res/network/virtual-network/subnet/README.md index e6269f8046..9a975d39da 100644 --- a/avm/res/network/virtual-network/subnet/README.md +++ b/avm/res/network/virtual-network/subnet/README.md @@ -144,6 +144,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/virtual-wan/README.md b/avm/res/network/virtual-wan/README.md index 18b3f54a3b..589165c1e2 100644 --- a/avm/res/network/virtual-wan/README.md +++ b/avm/res/network/virtual-wan/README.md @@ -56,7 +56,7 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-wan:' + +// Required parameters +param name = 'nvwmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -136,7 +152,7 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -204,6 +220,54 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-wan:' + +// Required parameters +param name = 'nvwmax001' +// Non-required parameters +param allowBranchToBranchTraffic = true +param allowVnetToVnetTraffic = true +param disableVpnEncryption = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '360a3e7e-49bf-4e94-839f-14c91e8e0c23' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param type = 'Basic' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -239,7 +303,7 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -280,6 +344,31 @@ module virtualWan 'br/public:avm/res/network/virtual-wan:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/virtual-wan:' + +// Required parameters +param name = 'nvwwaf001' +// Non-required parameters +param allowBranchToBranchTraffic = true +param allowVnetToVnetTraffic = true +param disableVpnEncryption = true +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param type = 'Basic' +``` + +
    +

    + ## Parameters **Required parameters** @@ -391,6 +480,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/network/vpn-gateway/README.md b/avm/res/network/vpn-gateway/README.md index cd27b9108d..26eec74c1c 100644 --- a/avm/res/network/vpn-gateway/README.md +++ b/avm/res/network/vpn-gateway/README.md @@ -59,7 +59,7 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,23 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngmin001' +param virtualHubResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -155,7 +172,7 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -234,6 +251,67 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngmax001' +param virtualHubResourceId = '' +// Non-required parameters +param bgpSettings = { + asn: 65515 + peerWeight: 0 +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnConnections = [ + { + connectionBandwidth: 100 + enableBgp: false + enableInternetSecurity: true + enableRateLimiting: false + name: '' + remoteVpnSiteResourceId: '' + routingWeight: 0 + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + vpnConnectionProtocolType: 'IKEv2' + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -305,7 +383,7 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -384,6 +462,67 @@ module vpnGateway 'br/public:avm/res/network/vpn-gateway:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-gateway:' + +// Required parameters +param name = 'vpngwaf001' +param virtualHubResourceId = '' +// Non-required parameters +param bgpSettings = { + asn: 65515 + peerWeight: 0 +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param natRules = [ + { + externalMappings: [ + { + addressSpace: '192.168.21.0/24' + } + ] + internalMappings: [ + { + addressSpace: '10.4.0.0/24' + } + ] + mode: 'EgressSnat' + name: 'natRule1' + type: 'Static' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vpnConnections = [ + { + connectionBandwidth: 100 + enableBgp: false + enableInternetSecurity: true + enableRateLimiting: false + name: '' + remoteVpnSiteResourceId: '' + routingWeight: 0 + useLocalAzureIpAddress: false + usePolicyBasedTrafficSelectors: false + vpnConnectionProtocolType: 'IKEv2' + } +] +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/network/vpn-server-configuration/README.md b/avm/res/network/vpn-server-configuration/README.md new file mode 100644 index 0000000000..a21f461ce1 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/README.md @@ -0,0 +1,1022 @@ +# VPN Server Configuration `[Microsoft.Network/vpnServerConfigurations]` + +This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [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.Network/vpnServerConfigurations` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/vpnServerConfigurations) | + +## 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/vpn-server-configuration:`. + +- [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 vpnServerConfiguration 'br/public:avm/res/network/vpn-server-configuration:' = { + name: 'vpnServerConfigurationDeployment' + params: { + // Required parameters + name: 'vscminVPNConfig' + // Non-required parameters + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + location: '' + p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vscminVPNConfig" + }, + // Non-required parameters + "aadAudience": { + "value": "11111111-1234-4321-1234-111111111111" + }, + "aadIssuer": { + "value": "https://sts.windows.net/11111111-1111-1111-1111-111111111111/" + }, + "aadTenant": { + "value": "https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111" + }, + "location": { + "value": "" + }, + "p2sConfigurationPolicyGroups": { + "value": [ + { + "isDefault": "true", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-2222-3333-111111111111", + "name": "UserGroup1" + } + ], + "priority": "0", + "userVPNPolicyGroupName": "DefaultGroup" + } + ] + }, + "vpnAuthenticationTypes": { + "value": [ + "AAD" + ] + }, + "vpnProtocols": { + "value": [ + "OpenVPN" + ] + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-server-configuration:' + +// Required parameters +param name = 'vscminVPNConfig' +// Non-required parameters +param aadAudience = '11111111-1234-4321-1234-111111111111' +param aadIssuer = 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' +param aadTenant = 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' +param location = '' +p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } +] +param vpnAuthenticationTypes = [ + 'AAD' +] +param vpnProtocols = [ + 'OpenVPN' +] +``` + +
    +

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

    + +via Bicep module + +```bicep +module vpnServerConfiguration 'br/public:avm/res/network/vpn-server-configuration:' = { + name: 'vpnServerConfigurationDeployment' + params: { + // Required parameters + name: 'vscmaxVPNConfig' + // Non-required parameters + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + location: '' + p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-3333-4444-111111111111' + name: 'UserGroup2' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + { + isDefault: 'false' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-4444-5555-111111111111' + name: 'UserGroup3' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-5555-6666-111111111111' + name: 'UserGroup4' + } + ] + priority: '1' + userVPNPolicyGroupName: 'AdditionalGroup' + } + ] + radiusClientRootCertificates: [ + { + name: 'TestRadiusClientRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b59aa' + } + ] + radiusServerRootCertificates: [ + { + name: 'TestRadiusRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + radiusServers: [ + { + radiusServerAddress: '10.150.1.50' + radiusServerScore: '10' + radiusServerSecret: 'TestSecret' + } + { + radiusServerAddress: '10.150.1.150' + radiusServerScore: '20' + radiusServerSecret: 'TestSecret2' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + 'Certificate' + 'Radius' + ] + vpnClientIpsecPolicies: [ + { + dhGroup: 'DHGroup14' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + pfsGroup: 'PFS14' + saDataSizeKilobytes: 0 + saLifeTimeSeconds: 27000 + } + ] + vpnClientRevokedCertificates: [ + { + name: 'TestRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69aa' + } + { + name: 'TestRevokedCert2' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69bb' + } + ] + vpnClientRootCertificates: [ + { + name: 'TestRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + { + name: 'TestRootCert2' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vscmaxVPNConfig" + }, + // Non-required parameters + "aadAudience": { + "value": "11111111-1234-4321-1234-111111111111" + }, + "aadIssuer": { + "value": "https://sts.windows.net/11111111-1111-1111-1111-111111111111/" + }, + "aadTenant": { + "value": "https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111" + }, + "location": { + "value": "" + }, + "p2sConfigurationPolicyGroups": { + "value": [ + { + "isDefault": "true", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-2222-3333-111111111111", + "name": "UserGroup1" + }, + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-3333-4444-111111111111", + "name": "UserGroup2" + } + ], + "priority": "0", + "userVPNPolicyGroupName": "DefaultGroup" + }, + { + "isDefault": "false", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-4444-5555-111111111111", + "name": "UserGroup3" + }, + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-5555-6666-111111111111", + "name": "UserGroup4" + } + ], + "priority": "1", + "userVPNPolicyGroupName": "AdditionalGroup" + } + ] + }, + "radiusClientRootCertificates": { + "value": [ + { + "name": "TestRadiusClientRevokedCert", + "thumbprint": "1f24c630cda418ef2069ffad4fdd5f463a1b59aa" + } + ] + }, + "radiusServerRootCertificates": { + "value": [ + { + "name": "TestRadiusRootCert", + "publicCertData": "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f" + } + ] + }, + "radiusServers": { + "value": [ + { + "radiusServerAddress": "10.150.1.50", + "radiusServerScore": "10", + "radiusServerSecret": "TestSecret" + }, + { + "radiusServerAddress": "10.150.1.150", + "radiusServerScore": "20", + "radiusServerSecret": "TestSecret2" + } + ] + }, + "vpnAuthenticationTypes": { + "value": [ + "AAD", + "Certificate", + "Radius" + ] + }, + "vpnClientIpsecPolicies": { + "value": [ + { + "dhGroup": "DHGroup14", + "ikeEncryption": "AES256", + "ikeIntegrity": "SHA256", + "ipsecEncryption": "AES256", + "ipsecIntegrity": "SHA256", + "pfsGroup": "PFS14", + "saDataSizeKilobytes": 0, + "saLifeTimeSeconds": 27000 + } + ] + }, + "vpnClientRevokedCertificates": { + "value": [ + { + "name": "TestRevokedCert", + "thumbprint": "1f24c630cda418ef2069ffad4fdd5f463a1b69aa" + }, + { + "name": "TestRevokedCert2", + "thumbprint": "1f24c630cda418ef2069ffad4fdd5f463a1b69bb" + } + ] + }, + "vpnClientRootCertificates": { + "value": [ + { + "name": "TestRootCert", + "publicCertData": "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f" + }, + { + "name": "TestRootCert2", + "publicCertData": "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f" + } + ] + }, + "vpnProtocols": { + "value": [ + "OpenVPN" + ] + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-server-configuration:' + +// Required parameters +param name = 'vscmaxVPNConfig' +// Non-required parameters +param aadAudience = '11111111-1234-4321-1234-111111111111' +param aadIssuer = 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' +param aadTenant = 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' +param location = '' +p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-3333-4444-111111111111' + name: 'UserGroup2' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + { + isDefault: 'false' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-4444-5555-111111111111' + name: 'UserGroup3' + } + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-5555-6666-111111111111' + name: 'UserGroup4' + } + ] + priority: '1' + userVPNPolicyGroupName: 'AdditionalGroup' + } +] +param radiusClientRootCertificates = [ + { + name: 'TestRadiusClientRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b59aa' + } +] +param radiusServerRootCertificates = [ + { + name: 'TestRadiusRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } +] +param radiusServers = [ + { + radiusServerAddress: '10.150.1.50' + radiusServerScore: '10' + radiusServerSecret: 'TestSecret' + } + { + radiusServerAddress: '10.150.1.150' + radiusServerScore: '20' + radiusServerSecret: 'TestSecret2' + } +] +param vpnAuthenticationTypes = [ + 'AAD' + 'Certificate' + 'Radius' +] +param vpnClientIpsecPolicies = [ + { + dhGroup: 'DHGroup14' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + pfsGroup: 'PFS14' + saDataSizeKilobytes: 0 + saLifeTimeSeconds: 27000 + } +] +param vpnClientRevokedCertificates = [ + { + name: 'TestRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69aa' + } + { + name: 'TestRevokedCert2' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69bb' + } +] +param vpnClientRootCertificates = [ + { + name: 'TestRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + { + name: 'TestRootCert2' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } +] +param vpnProtocols = [ + 'OpenVPN' +] +``` + +
    +

    + +### 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 vpnServerConfiguration 'br/public:avm/res/network/vpn-server-configuration:' = { + name: 'vpnServerConfigurationDeployment' + params: { + // Required parameters + name: 'vscwafVPNConfig' + // Non-required parameters + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + location: '' + p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "vscwafVPNConfig" + }, + // Non-required parameters + "aadAudience": { + "value": "11111111-1234-4321-1234-111111111111" + }, + "aadIssuer": { + "value": "https://sts.windows.net/11111111-1111-1111-1111-111111111111/" + }, + "aadTenant": { + "value": "https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111" + }, + "location": { + "value": "" + }, + "p2sConfigurationPolicyGroups": { + "value": [ + { + "isDefault": "true", + "policymembers": [ + { + "attributeType": "AADGroupId", + "attributeValue": "11111111-1111-2222-3333-111111111111", + "name": "UserGroup1" + } + ], + "priority": "0", + "userVPNPolicyGroupName": "DefaultGroup" + } + ] + }, + "vpnAuthenticationTypes": { + "value": [ + "AAD" + ] + }, + "vpnProtocols": { + "value": [ + "OpenVPN" + ] + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-server-configuration:' + +// Required parameters +param name = 'vscwafVPNConfig' +// Non-required parameters +param aadAudience = '11111111-1234-4321-1234-111111111111' +param aadIssuer = 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' +param aadTenant = 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' +param location = '' +p2sConfigurationPolicyGroups: [ + { + isDefault: 'true' + policymembers: [ + { + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + name: 'UserGroup1' + } + ] + priority: '0' + userVPNPolicyGroupName: 'DefaultGroup' + } +] +param vpnAuthenticationTypes = [ + 'AAD' +] +param vpnProtocols = [ + 'OpenVPN' +] +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the user VPN configuration. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aadAudience`](#parameter-aadaudience) | string | The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. | +| [`aadIssuer`](#parameter-aadissuer) | string | The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication. | +| [`aadTenant`](#parameter-aadtenant) | string | The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. | +| [`radiusServerAddress`](#parameter-radiusserveraddress) | string | The address of the RADIUS server. Required if configuring a single RADIUS. | +| [`radiusServerSecret`](#parameter-radiusserversecret) | securestring | The RADIUS server secret. Required if configuring a single RADIUS server. | +| [`vpnClientRootCertificates`](#parameter-vpnclientrootcertificates) | array | The VPN Client root certificate public keys for the configuration. Required if using certificate authentication. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location where all resources will be created. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`p2sConfigurationPolicyGroups`](#parameter-p2sconfigurationpolicygroups) | array | The P2S configuration policy groups for the configuration. | +| [`radiusClientRootCertificates`](#parameter-radiusclientrootcertificates) | array | The revoked RADIUS client certificates for the configuration. | +| [`radiusServerRootCertificates`](#parameter-radiusserverrootcertificates) | array | The root certificates of the RADIUS server. | +| [`radiusServers`](#parameter-radiusservers) | array | The list of RADIUS servers. Required if configuring multiple RADIUS servers. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vpnAuthenticationTypes`](#parameter-vpnauthenticationtypes) | array | The authentication types for the VPN configuration. | +| [`vpnClientIpsecPolicies`](#parameter-vpnclientipsecpolicies) | array | The IPsec policies for the configuration. | +| [`vpnClientRevokedCertificates`](#parameter-vpnclientrevokedcertificates) | array | The revoked VPN Client certificate thumbprints for the configuration. | +| [`vpnProtocols`](#parameter-vpnprotocols) | array | The allowed VPN protocols for the configuration. | + +### Parameter: `name` + +The name of the user VPN configuration. + +- Required: Yes +- Type: string + +### Parameter: `aadAudience` + +The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. + +- Required: No +- Type: string + +### Parameter: `aadIssuer` + +The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication. + +- Required: No +- Type: string + +### Parameter: `aadTenant` + +The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication. + +- Required: No +- Type: string + +### Parameter: `radiusServerAddress` + +The address of the RADIUS server. Required if configuring a single RADIUS. + +- Required: No +- Type: string + +### Parameter: `radiusServerSecret` + +The RADIUS server secret. Required if configuring a single RADIUS server. + +- Required: No +- Type: securestring + +### Parameter: `vpnClientRootCertificates` + +The VPN Client root certificate public keys for the configuration. Required if using certificate authentication. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location where all resources will be created. + +- 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: `p2sConfigurationPolicyGroups` + +The P2S configuration policy groups for the configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `radiusClientRootCertificates` + +The revoked RADIUS client certificates for the configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `radiusServerRootCertificates` + +The root certificates of the RADIUS server. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `radiusServers` + +The list of RADIUS servers. Required if configuring multiple RADIUS servers. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vpnAuthenticationTypes` + +The authentication types for the VPN configuration. + +- Required: No +- Type: array +- Default: `[]` +- Allowed: + ```Bicep + [ + 'AAD' + 'Certificate' + 'Radius' + ] + ``` + +### Parameter: `vpnClientIpsecPolicies` + +The IPsec policies for the configuration. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dhGroup`](#parameter-vpnclientipsecpoliciesdhgroup) | string | The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2. | +| [`ikeEncryption`](#parameter-vpnclientipsecpoliciesikeencryption) | string | The encryption algorithm used in IKE phase 1. Required if using IKEv2. | +| [`ikeIntegrity`](#parameter-vpnclientipsecpoliciesikeintegrity) | string | The integrity algorithm used in IKE phase 1. Required if using IKEv2. | +| [`ipsecEncryption`](#parameter-vpnclientipsecpoliciesipsecencryption) | string | The encryption algorithm used in IKE phase 2. Required if using IKEv2. | +| [`ipsecIntegrity`](#parameter-vpnclientipsecpoliciesipsecintegrity) | string | The integrity algorithm used in IKE phase 2. Required if using IKEv2. | +| [`pfsGroup`](#parameter-vpnclientipsecpoliciespfsgroup) | string | The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2. | +| [`saDataSizeKilobytes`](#parameter-vpnclientipsecpoliciessadatasizekilobytes) | int | The size of the SA data in kilobytes. Required if using IKEv2. | +| [`salfetimeSeconds`](#parameter-vpnclientipsecpoliciessalfetimeseconds) | int | The lifetime of the SA in seconds. Required if using IKEv2. | + +### Parameter: `vpnClientIpsecPolicies.dhGroup` + +The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ikeEncryption` + +The encryption algorithm used in IKE phase 1. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ikeIntegrity` + +The integrity algorithm used in IKE phase 1. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ipsecEncryption` + +The encryption algorithm used in IKE phase 2. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.ipsecIntegrity` + +The integrity algorithm used in IKE phase 2. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.pfsGroup` + +The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2. + +- Required: No +- Type: string + +### Parameter: `vpnClientIpsecPolicies.saDataSizeKilobytes` + +The size of the SA data in kilobytes. Required if using IKEv2. + +- Required: No +- Type: int + +### Parameter: `vpnClientIpsecPolicies.salfetimeSeconds` + +The lifetime of the SA in seconds. Required if using IKEv2. + +- Required: No +- Type: int + +### Parameter: `vpnClientRevokedCertificates` + +The revoked VPN Client certificate thumbprints for the configuration. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `vpnProtocols` + +The allowed VPN protocols for the configuration. + +- Required: No +- Type: array +- Default: `[]` +- Allowed: + ```Bicep + [ + 'IkeV2' + 'OpenVPN' + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the user VPN configuration. | +| `resourceGroupName` | string | The name of the resource group the user VPN configuration was deployed into. | +| `resourceId` | string | The resource ID of the user VPN configuration. | + +## 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/vpn-server-configuration/main.bicep b/avm/res/network/vpn-server-configuration/main.bicep new file mode 100644 index 0000000000..b4a86adba5 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/main.bicep @@ -0,0 +1,224 @@ +metadata name = 'VPN Server Configuration' +metadata description = 'This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the user VPN configuration.') +param name string + +@description('Optional. Location where all resources will be created.') +param location string = resourceGroup().location + +@description('Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication.') +param aadAudience string? + +@description('Conditional. The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication.') +param aadIssuer string? + +@description('Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication.') +param aadTenant string? + +@description('Optional. The P2S configuration policy groups for the configuration.') +param p2sConfigurationPolicyGroups array = [] + +@description('Optional. The revoked RADIUS client certificates for the configuration.') +param radiusClientRootCertificates array = [] + +@description('Conditional. The address of the RADIUS server. Required if configuring a single RADIUS.') +param radiusServerAddress string? + +@description('Optional. The root certificates of the RADIUS server.') +param radiusServerRootCertificates array = [] + +@description('Optional. The list of RADIUS servers. Required if configuring multiple RADIUS servers.') +param radiusServers array = [] + +@description('Conditional. The RADIUS server secret. Required if configuring a single RADIUS server.') +@secure() +param radiusServerSecret string? + +@description('Optional. The authentication types for the VPN configuration.') +@allowed([ + 'AAD' + 'Certificate' + 'Radius' +]) +param vpnAuthenticationTypes array = [] + +@description('Optional. The IPsec policies for the configuration.') +param vpnClientIpsecPolicies vpnClientIpsecPoliciesType[]? + +@description('Optional. The revoked VPN Client certificate thumbprints for the configuration.') +param vpnClientRevokedCertificates array = [] + +@description('Conditional. The VPN Client root certificate public keys for the configuration. Required if using certificate authentication.') +param vpnClientRootCertificates array = [] + +@description('Optional. The allowed VPN protocols for the configuration.') +@allowed([ + 'IkeV2' + 'OpenVPN' +]) +param vpnProtocols array = [] + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: take( + '46d3xbcp.res.network-vpnserverconfiguration.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}', + 64 + ) + 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 vpnServerConfig 'Microsoft.Network/vpnServerConfigurations@2023-11-01' = { + name: name + location: location + tags: tags + properties: { + aadAuthenticationParameters: { + aadAudience: aadAudience + aadIssuer: aadIssuer + aadTenant: aadTenant + } + configurationPolicyGroups: [ + for group in (p2sConfigurationPolicyGroups) ?? []: { + name: group.userVPNPolicyGroupName + properties: { + isDefault: group.isDefault + policyMembers: group.policyMembers + priority: group.priority + } + } + ] + radiusClientRootCertificates: [ + for clientRootroot in (radiusClientRootCertificates) ?? []: { + name: clientRootroot.name + thumbprint: clientRootroot.thumbprint + } + ] + radiusServerAddress: radiusServerAddress + radiusServerRootCertificates: [ + for serverRoot in (radiusServerRootCertificates) ?? []: { + name: serverRoot.name + publicCertData: serverRoot.publicCertData + } + ] + radiusServers: [ + for server in (radiusServers) ?? []: { + radiusServerAddress: server.radiusServerAddress + radiusServerScore: server.radiusServerScore + radiusServerSecret: server.radiusServerSecret + } + ] + radiusServerSecret: radiusServerSecret + vpnAuthenticationTypes: vpnAuthenticationTypes + vpnClientIpsecPolicies: [ + for policy in (vpnClientIpsecPolicies) ?? []: { + dhGroup: policy.dhGroup + ikeEncryption: policy.ikeEncryption + ikeIntegrity: policy.ikeIntegrity + ipsecEncryption: policy.ipsecEncryption + ipsecIntegrity: policy.ipsecIntegrity + pfsGroup: policy.pfsGroup + saDataSizeKilobytes: policy.saDataSizeKilobytes + saLifeTimeSeconds: policy.saLifeTimeSeconds + } + ] + vpnClientRevokedCertificates: [ + for cert in (vpnClientRevokedCertificates) ?? []: { + name: cert.name + thumbprint:cert.thumbprint + } + ] + vpnClientRootCertificates: [ + for cert in (vpnClientRootCertificates) ?? []: { + name: cert.name + publicCertData: cert.publicCertData + } + ] + vpnProtocols: vpnProtocols + } +} + +resource vpnGateway_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: vpnServerConfig +} + +@description('The name of the user VPN configuration.') +output name string = vpnServerConfig.name + +@description('The resource ID of the user VPN configuration.') +output resourceId string = vpnServerConfig.id + +@description('The name of the resource group the user VPN configuration was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = vpnServerConfig.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +@export() +type vpnClientIpsecPoliciesType = { + @description('Optional. The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2.') + dhGroup: string? + + @description('Optional. The encryption algorithm used in IKE phase 1. Required if using IKEv2.') + ikeEncryption: string? + + @description('Optional. The integrity algorithm used in IKE phase 1. Required if using IKEv2.') + ikeIntegrity: string? + + @description('Optional. The encryption algorithm used in IKE phase 2. Required if using IKEv2.') + ipsecEncryption: string? + + @description('Optional. The integrity algorithm used in IKE phase 2. Required if using IKEv2.') + ipsecIntegrity: string? + + @description('Optional. The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2.') + pfsGroup: string? + + @description('Optional. The size of the SA data in kilobytes. Required if using IKEv2.') + saDataSizeKilobytes: int? + + @description('Optional. The lifetime of the SA in seconds. Required if using IKEv2.') + salfetimeSeconds: int? +} diff --git a/avm/res/network/vpn-server-configuration/main.json b/avm/res/network/vpn-server-configuration/main.json new file mode 100644 index 0000000000..c7b7b25c43 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/main.json @@ -0,0 +1,404 @@ +{ + "$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.30.23.60470", + "templateHash": "17638255215829732671" + }, + "name": "VPN Server Configuration", + "description": "This module deploys a VPN Server Configuration for a Virtual Hub P2S Gateway.", + "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 + }, + "vpnClientIpsecPoliciesType": { + "type": "object", + "properties": { + "dhGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Diffie-Hellman group used in IKE phase 1. Required if using IKEv2." + } + }, + "ikeEncryption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The encryption algorithm used in IKE phase 1. Required if using IKEv2." + } + }, + "ikeIntegrity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The integrity algorithm used in IKE phase 1. Required if using IKEv2." + } + }, + "ipsecEncryption": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The encryption algorithm used in IKE phase 2. Required if using IKEv2." + } + }, + "ipsecIntegrity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The integrity algorithm used in IKE phase 2. Required if using IKEv2." + } + }, + "pfsGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Perfect Forward Secrecy (PFS) group used in IKE phase 2. Required if using IKEv2." + } + }, + "saDataSizeKilobytes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The size of the SA data in kilobytes. Required if using IKEv2." + } + }, + "salfetimeSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The lifetime of the SA in seconds. Required if using IKEv2." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the user VPN configuration." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location where all resources will be created." + } + }, + "aadAudience": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication." + } + }, + "aadIssuer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The issuer for the AAD/Entra authentication. Required if configuring Entra ID authentication." + } + }, + "aadTenant": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The audience for the AAD/Entra authentication. Required if configuring Entra ID authentication." + } + }, + "p2sConfigurationPolicyGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The P2S configuration policy groups for the configuration." + } + }, + "radiusClientRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The revoked RADIUS client certificates for the configuration." + } + }, + "radiusServerAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The address of the RADIUS server. Required if configuring a single RADIUS." + } + }, + "radiusServerRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The root certificates of the RADIUS server." + } + }, + "radiusServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The list of RADIUS servers. Required if configuring multiple RADIUS servers." + } + }, + "radiusServerSecret": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Conditional. The RADIUS server secret. Required if configuring a single RADIUS server." + } + }, + "vpnAuthenticationTypes": { + "type": "array", + "defaultValue": [], + "allowedValues": [ + "AAD", + "Certificate", + "Radius" + ], + "metadata": { + "description": "Optional. The authentication types for the VPN configuration." + } + }, + "vpnClientIpsecPolicies": { + "type": "array", + "items": { + "$ref": "#/definitions/vpnClientIpsecPoliciesType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The IPsec policies for the configuration." + } + }, + "vpnClientRevokedCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The revoked VPN Client certificate thumbprints for the configuration." + } + }, + "vpnClientRootCertificates": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Conditional. The VPN Client root certificate public keys for the configuration. Required if using certificate authentication." + } + }, + "vpnProtocols": { + "type": "array", + "defaultValue": [], + "allowedValues": [ + "IkeV2", + "OpenVPN" + ], + "metadata": { + "description": "Optional. The allowed VPN protocols for the configuration." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[take(format('46d3xbcp.res.network-vpnserverconfiguration.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "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" + } + } + } + } + }, + "vpnServerConfig": { + "type": "Microsoft.Network/vpnServerConfigurations", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "configurationPolicyGroups", + "count": "[length(coalesce(parameters('p2sConfigurationPolicyGroups'), createArray()))]", + "input": { + "name": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].userVPNPolicyGroupName]", + "properties": { + "isDefault": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].isDefault]", + "policyMembers": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].policyMembers]", + "priority": "[coalesce(parameters('p2sConfigurationPolicyGroups'), createArray())[copyIndex('configurationPolicyGroups')].priority]" + } + } + }, + { + "name": "radiusClientRootCertificates", + "count": "[length(coalesce(parameters('radiusClientRootCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('radiusClientRootCertificates'), createArray())[copyIndex('radiusClientRootCertificates')].name]", + "thumbprint": "[coalesce(parameters('radiusClientRootCertificates'), createArray())[copyIndex('radiusClientRootCertificates')].thumbprint]" + } + }, + { + "name": "radiusServerRootCertificates", + "count": "[length(coalesce(parameters('radiusServerRootCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('radiusServerRootCertificates'), createArray())[copyIndex('radiusServerRootCertificates')].name]", + "publicCertData": "[coalesce(parameters('radiusServerRootCertificates'), createArray())[copyIndex('radiusServerRootCertificates')].publicCertData]" + } + }, + { + "name": "radiusServers", + "count": "[length(coalesce(parameters('radiusServers'), createArray()))]", + "input": { + "radiusServerAddress": "[coalesce(parameters('radiusServers'), createArray())[copyIndex('radiusServers')].radiusServerAddress]", + "radiusServerScore": "[coalesce(parameters('radiusServers'), createArray())[copyIndex('radiusServers')].radiusServerScore]", + "radiusServerSecret": "[coalesce(parameters('radiusServers'), createArray())[copyIndex('radiusServers')].radiusServerSecret]" + } + }, + { + "name": "vpnClientIpsecPolicies", + "count": "[length(coalesce(parameters('vpnClientIpsecPolicies'), createArray()))]", + "input": { + "dhGroup": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].dhGroup]", + "ikeEncryption": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ikeEncryption]", + "ikeIntegrity": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ikeIntegrity]", + "ipsecEncryption": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ipsecEncryption]", + "ipsecIntegrity": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].ipsecIntegrity]", + "pfsGroup": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].pfsGroup]", + "saDataSizeKilobytes": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].saDataSizeKilobytes]", + "saLifeTimeSeconds": "[coalesce(parameters('vpnClientIpsecPolicies'), createArray())[copyIndex('vpnClientIpsecPolicies')].saLifeTimeSeconds]" + } + }, + { + "name": "vpnClientRevokedCertificates", + "count": "[length(coalesce(parameters('vpnClientRevokedCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('vpnClientRevokedCertificates'), createArray())[copyIndex('vpnClientRevokedCertificates')].name]", + "thumbprint": "[coalesce(parameters('vpnClientRevokedCertificates'), createArray())[copyIndex('vpnClientRevokedCertificates')].thumbprint]" + } + }, + { + "name": "vpnClientRootCertificates", + "count": "[length(coalesce(parameters('vpnClientRootCertificates'), createArray()))]", + "input": { + "name": "[coalesce(parameters('vpnClientRootCertificates'), createArray())[copyIndex('vpnClientRootCertificates')].name]", + "publicCertData": "[coalesce(parameters('vpnClientRootCertificates'), createArray())[copyIndex('vpnClientRootCertificates')].publicCertData]" + } + } + ], + "aadAuthenticationParameters": { + "aadAudience": "[parameters('aadAudience')]", + "aadIssuer": "[parameters('aadIssuer')]", + "aadTenant": "[parameters('aadTenant')]" + }, + "radiusServerAddress": "[parameters('radiusServerAddress')]", + "radiusServerSecret": "[parameters('radiusServerSecret')]", + "vpnAuthenticationTypes": "[parameters('vpnAuthenticationTypes')]", + "vpnProtocols": "[parameters('vpnProtocols')]" + } + }, + "vpnGateway_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/vpnServerConfigurations/{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": [ + "vpnServerConfig" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user VPN configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user VPN configuration." + }, + "value": "[resourceId('Microsoft.Network/vpnServerConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the user VPN configuration was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('vpnServerConfig', '2023-11-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..3e28ec067b --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id diff --git a/avm/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..0a4ae3b7e7 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,82 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.vpnserverconfiguration-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'vscmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + + + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}VPNConfig' + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + p2sConfigurationPolicyGroups: [ + { + userVPNPolicyGroupName: 'DefaultGroup' + policymembers: [ + { + name: 'UserGroup1' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + } + ] + priority: '0' + isDefault: 'true' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } + } +] diff --git a/avm/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..3e28ec067b --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/max/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWANResourceId string = virtualWan.id diff --git a/avm/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..f40181a92a --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/max/main.test.bicep @@ -0,0 +1,163 @@ +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) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-network.vpnserverconfiguration-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'vscmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}VPNConfig' + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + p2sConfigurationPolicyGroups: [ + { + userVPNPolicyGroupName: 'DefaultGroup' + policymembers: [ + { + name: 'UserGroup1' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + } + { + name: 'UserGroup2' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-3333-4444-111111111111' + } + ] + priority: '0' + isDefault: 'true' + } + { + userVPNPolicyGroupName: 'AdditionalGroup' + policymembers: [ + { + name: 'UserGroup3' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-4444-5555-111111111111' + } + { + name: 'UserGroup4' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-5555-6666-111111111111' + } + ] + priority: '1' + isDefault: 'false' + } + ] + radiusServers: [ + { + radiusServerAddress: '10.150.1.50' + radiusServerScore: '10' + radiusServerSecret: 'TestSecret' + } + { + radiusServerAddress: '10.150.1.150' + radiusServerScore: '20' + radiusServerSecret: 'TestSecret2' + } + ] + radiusServerRootCertificates: [ + { + name: 'TestRadiusRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + radiusClientRootCertificates: [ + { + name: 'TestRadiusClientRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b59aa' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + 'Certificate' + 'Radius' + ] + vpnClientIpsecPolicies: [ + { + saLifeTimeSeconds: 27000 + saDataSizeKilobytes: 0 + ipsecEncryption: 'AES256' + ipsecIntegrity: 'SHA256' + ikeEncryption: 'AES256' + ikeIntegrity: 'SHA256' + dhGroup: 'DHGroup14' + pfsGroup: 'PFS14' + } + ] + vpnClientRevokedCertificates: [ + { + name: 'TestRevokedCert' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69aa' + } + { + name: 'TestRevokedCert2' + thumbprint: '1f24c630cda418ef2069ffad4fdd5f463a1b69bb' + } + ] + vpnClientRootCertificates: [ + { + name: 'TestRootCert' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + { + name: 'TestRootCert2' + publicCertData: 'MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcMARELBQAwTDEgMB4GA1UECxMXR4xvYmFsU2lnbiBSb390IENBIC0gUjMxEzARBgNVBAoTCkdsb8JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD8f' + } + ] + vpnProtocols: [ + 'OpenVPN' + ] + } + } +] diff --git a/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..bb151ad9d8 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Required. The name of the virtual WAN to create.') +param virtualWANName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +resource virtualWan 'Microsoft.Network/virtualWans@2023-04-01' = { + name: virtualWANName + location: location +} + +@description('The resource ID of the created Virtual WAN.') +output virtualWWANResourceId string = virtualWan.id diff --git a/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..02e29e4f93 --- /dev/null +++ b/avm/res/network/vpn-server-configuration/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,83 @@ +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) +// e.g., for a module 'network/private-endpoint' you could use 'dep-dev-network.privateendpoints-${serviceShort}-rg' +param resourceGroupName string = 'dep-${namePrefix}-network.vpnserverconfiguration-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +// e.g., for a module 'network/private-endpoint' you could use 'npe' as a prefix and then 'waf' as a suffix for the waf-aligned test +param serviceShort string = 'vscwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + virtualWANName: 'dep-${namePrefix}-vw-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}VPNConfig' + aadAudience: '11111111-1234-4321-1234-111111111111' + aadIssuer: 'https://sts.windows.net/11111111-1111-1111-1111-111111111111/' + aadTenant: 'https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111' + p2sConfigurationPolicyGroups: [ + { + userVPNPolicyGroupName: 'DefaultGroup' + policymembers: [ + { + name: 'UserGroup1' + attributeType: 'AADGroupId' + attributeValue: '11111111-1111-2222-3333-111111111111' + } + ] + priority: '0' + isDefault: 'true' + } + ] + vpnAuthenticationTypes: [ + 'AAD' + ] + vpnProtocols: [ + 'OpenVPN' + ] + } + } +] diff --git a/avm/res/network/vpn-server-configuration/version.json b/avm/res/network/vpn-server-configuration/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/network/vpn-server-configuration/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/network/vpn-site/README.md b/avm/res/network/vpn-site/README.md index 07e306d08b..92f162d8a7 100644 --- a/avm/res/network/vpn-site/README.md +++ b/avm/res/network/vpn-site/README.md @@ -62,7 +62,7 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -95,6 +95,27 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-site:' + +// Required parameters +param name = 'nvsmin' +param virtualWanId = '' +// Non-required parameters +param addressPrefixes = [ + '10.0.0.0/16' +] +param ipAddress = '1.2.3.4' +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -190,7 +211,7 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -295,6 +316,91 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-site:' + +// Required parameters +param name = 'nvsmax' +param virtualWanId = '' +// Non-required parameters +param deviceProperties = { + linkSpeedInMbps: 0 +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +o365Policy: { + breakOutCategories: { + allow: true + default: true + optimize: true + } +} +param roleAssignments = [ + { + name: '1dcfa9c2-5e95-42d2-bf04-bdecad93abcf' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' +} +param vpnSiteLinks = [ + { + name: 'vSite-nvsmax' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -371,7 +477,7 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -455,6 +561,72 @@ module vpnSite 'br/public:avm/res/network/vpn-site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/vpn-site:' + +// Required parameters +param name = 'nvswaf' +param virtualWanId = '' +// Non-required parameters +param deviceProperties = { + linkSpeedInMbps: 0 +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +o365Policy: { + breakOutCategories: { + allow: true + default: true + optimize: true + } +} +param tags = { + 'hidden-title': 'This is visible in the resource name' + tagA: 'valueA' + tagB: 'valueB' +} +param vpnSiteLinks = [ + { + name: 'vSite-nvswaf' + properties: { + bgpProperties: { + asn: 65010 + bgpPeeringAddress: '1.1.1.1' + } + ipAddress: '1.2.3.4' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } + { + name: 'Link1' + properties: { + bgpProperties: { + asn: 65020 + bgpPeeringAddress: '192.168.1.0' + } + ipAddress: '2.2.2.2' + linkProperties: { + linkProviderName: 'contoso' + linkSpeedInMbps: 5 + } + } + } +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -606,6 +778,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Network Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/operational-insights/workspace/README.md b/avm/res/operational-insights/workspace/README.md index 2290266bfb..40a8d48755 100644 --- a/avm/res/operational-insights/workspace/README.md +++ b/avm/res/operational-insights/workspace/README.md @@ -344,7 +344,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -673,6 +673,299 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwadv001' +// Non-required parameters +param dailyQuotaGb = 10 +param dataExports = [ + { + destination: { + metaData: { + eventHubName: '' + } + resourceId: '' + } + enable: true + name: 'eventHubExport' + tableNames: [ + 'Alert' + 'InsightsMetrics' + ] + } + { + destination: { + resourceId: '' + } + enable: true + name: 'storageAccountExport' + tableNames: [ + 'Operation' + ] + } +] +param dataSources = [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + { + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'sendingDiagnosticSettingsToSelf' + useThisWorkspace: true + } +] +param gallerySolutions = [ + { + name: 'AzureAutomation' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + resourceId: '' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param publicNetworkAccessForIngestion = 'Disabled' +param publicNetworkAccessForQuery = 'Disabled' +param savedSearches = [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + } +] +param storageInsightsConfigs = [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } +] +param tables = [ + { + name: 'CustomTableBasic_CL' + retentionInDays: 60 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'RawData' + type: 'String' + } + ] + name: 'CustomTableBasic_CL' + } + totalRetentionInDays: 90 + } + { + name: 'CustomTableAdvanced_CL' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'EventTime' + type: 'DateTime' + } + { + name: 'EventLevel' + type: 'String' + } + { + name: 'EventCode' + type: 'Int' + } + { + name: 'Message' + type: 'String' + } + { + name: 'RawData' + type: 'String' + } + ] + name: 'CustomTableAdvanced_CL' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param useResourcePermissions = true +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -699,7 +992,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -721,6 +1014,22 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -1020,7 +1329,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1347,6 +1656,295 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwmax001' +// Non-required parameters +param dailyQuotaGb = 10 +param dataSources = [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gallerySolutions = [ + { + name: 'AzureAutomation' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + resourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param publicNetworkAccessForIngestion = 'Disabled' +param publicNetworkAccessForQuery = 'Disabled' +param roleAssignments = [ + { + name: 'c3d53092-840c-4025-9c02-9bcb7895789c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param savedSearches = [ + { + category: 'VDC Saved Searches' + displayName: 'VMSS Instance Count2' + name: 'VMSSQueries' + query: 'Event | where Source == ServiceFabricNodeBootstrapAgent | summarize AggregatedValue = count() by Computer' + tags: [ + { + Name: 'Environment' + Value: 'Non-Prod' + } + { + Name: 'Role' + Value: 'DeploymentValidation' + } + ] + } +] +param storageInsightsConfigs = [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } +] +param tables = [ + { + name: 'CustomTableBasic_CL' + retentionInDays: 60 + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'RawData' + type: 'String' + } + ] + name: 'CustomTableBasic_CL' + } + totalRetentionInDays: 90 + } + { + name: 'CustomTableAdvanced_CL' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + schema: { + columns: [ + { + name: 'TimeGenerated' + type: 'DateTime' + } + { + name: 'EventTime' + type: 'DateTime' + } + { + name: 'EventLevel' + type: 'String' + } + { + name: 'EventCode' + type: 'Int' + } + { + name: 'Message' + type: 'String' + } + { + name: 'RawData' + type: 'String' + } + ] + name: 'CustomTableAdvanced_CL' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param useResourcePermissions = true +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1513,7 +2111,7 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1699,6 +2297,162 @@ module workspace 'br/public:avm/res/operational-insights/workspace:' =

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operational-insights/workspace:' + +// Required parameters +param name = 'oiwwaf001' +// Non-required parameters +param dailyQuotaGb = 10 +param dataSources = [ + { + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + { + kind: 'LinuxSyslog' + name: 'sampleSyslog1' + syslogName: 'kern' + syslogSeverities: [ + { + severity: 'emerg' + } + { + severity: 'alert' + } + { + severity: 'crit' + } + { + severity: 'err' + } + { + severity: 'warning' + } + ] + } + { + kind: 'LinuxSyslogCollection' + name: 'sampleSyslogCollection1' + state: 'Enabled' + } + { + instanceName: '*' + intervalSeconds: 10 + kind: 'LinuxPerformanceObject' + name: 'sampleLinuxPerf1' + objectName: 'Logical Disk' + syslogSeverities: [ + { + counterName: '% Used Inodes' + } + { + counterName: 'Free Megabytes' + } + { + counterName: '% Used Space' + } + { + counterName: 'Disk Transfers/sec' + } + { + counterName: 'Disk Reads/sec' + } + { + counterName: 'Disk Writes/sec' + } + ] + } + { + kind: 'LinuxPerformanceCollection' + name: 'sampleLinuxPerfCollection1' + state: 'Enabled' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param gallerySolutions = [ + { + name: 'AzureAutomation' + product: 'OMSGallery' + publisher: 'Microsoft' + } +] +param linkedServices = [ + { + name: 'Automation' + resourceId: '' + } +] +param linkedStorageAccounts = [ + { + name: 'Query' + resourceId: '' + } +] +param location = '' +param managedIdentities = { + systemAssigned: true +} +param publicNetworkAccessForIngestion = 'Disabled' +param publicNetworkAccessForQuery = 'Disabled' +param storageInsightsConfigs = [ + { + storageAccountResourceId: '' + tables: [ + 'LinuxsyslogVer2v0' + 'WADETWEventTable' + 'WADServiceFabric*EventTable' + 'WADWindowsEventLogsTable' + ] + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param useResourcePermissions = true +``` + +
    +

    + ## Parameters **Required parameters** @@ -2081,6 +2835,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Security Admin'` + - `'Security Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/operational-insights/workspace/table/README.md b/avm/res/operational-insights/workspace/table/README.md index 7313d497ee..dc20f643c0 100644 --- a/avm/res/operational-insights/workspace/table/README.md +++ b/avm/res/operational-insights/workspace/table/README.md @@ -92,6 +92,16 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Monitoring Contributor'` + - `'Monitoring Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/operations-management/solution/README.md b/avm/res/operations-management/solution/README.md index 42365f2274..f8f05da8f6 100644 --- a/avm/res/operations-management/solution/README.md +++ b/avm/res/operations-management/solution/README.md @@ -56,7 +56,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -81,6 +81,23 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'Updates' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Microsoft solution_ This instance deploys the module with a Microsoft solution. @@ -110,7 +127,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -141,6 +158,25 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'AzureAutomation' +// Non-required parameters +param location = '' +param product = 'OMSGallery' +param publisher = 'Microsoft' +``` + +
    +

    + ### Example 3: _Non-Microsoft solution_ This instance deploys the module with a third party (Non-Microsoft) solution. @@ -170,7 +206,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -201,6 +237,25 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'omsnonms001' +// Non-required parameters +param location = '' +param product = 'nonmsTestSolutionProduct' +param publisher = 'nonmsTestSolutionPublisher' +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -230,7 +285,7 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -261,6 +316,25 @@ module solution 'br/public:avm/res/operations-management/solution:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/operations-management/solution:' + +// Required parameters +param logAnalyticsWorkspaceName = '' +param name = 'AzureAutomation' +// Non-required parameters +param location = '' +param product = 'OMSGallery' +param publisher = 'Microsoft' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/portal/dashboard/README.md b/avm/res/portal/dashboard/README.md index 0a33b644ff..63cc4e5a9b 100644 --- a/avm/res/portal/dashboard/README.md +++ b/avm/res/portal/dashboard/README.md @@ -56,7 +56,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/portal/dashboard:' + +// Required parameters +param name = 'pdmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -236,7 +252,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -400,6 +416,154 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/portal/dashboard:' + +// Required parameters +param name = 'pdmax001' +// Non-required parameters +param lenses = [ + { + order: 0 + parts: [ + { + metadata: { + inputs: [] + type: 'Extension/Microsoft_Azure_Security/PartType/SecurityMetricGalleryTileViewModel' + } + position: { + colSpan: 2 + rowSpan: 3 + x: 0 + y: 0 + } + } + { + metadata: { + inputs: [ + { + isOptional: true + name: 'isShared' + } + { + isOptional: true + name: 'queryId' + } + { + isOptional: true + name: 'formatResults' + } + { + isOptional: true + name: 'partTitle' + value: 'Query 1' + } + { + isOptional: true + name: 'chartType' + value: 1 + } + { + isOptional: true + name: 'queryScope' + value: { + scope: 0 + values: [] + } + } + { + isOptional: true + name: 'query' + value: 'summarize ResourceCount=count() by type\n| order by ResourceCount desc\n| take 5\n| project [\'Resource Type\']=type, [\'Resource Count\']=ResourceCount' + } + ] + partHeader: { + subtitle: '' + title: 'Top 5 resource types' + } + settings: {} + type: 'Extension/HubsExtension/PartType/ArgQueryChartTile' + } + position: { + colSpan: 9 + rowSpan: 3 + x: 2 + y: 0 + } + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param metadata = { + model: { + filterLocale: { + value: 'en-us' + } + filters: { + value: { + MsPortalFx_TimeRange: { + displayCache: { + name: 'UTC Time' + value: 'Past 24 hours' + } + filteredPartIds: [] + model: { + format: 'utc' + granularity: 'auto' + relative: '24h' + } + } + } + } + timeRange: { + type: 'MsPortalFx.Composition.Configuration.ValueTypes.TimeRange' + value: { + relative: { + duration: 24 + timeUnit: 1 + } + } + } + } +} +param roleAssignments = [ + { + name: '15e2e690-5c9f-4cbf-9716-94ee73efab8b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -547,7 +711,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -696,6 +860,143 @@ module dashboard 'br/public:avm/res/portal/dashboard:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/portal/dashboard:' + +// Required parameters +param name = 'pdwaf001' +// Non-required parameters +param lenses = [ + { + order: 0 + parts: [ + { + metadata: { + inputs: [] + settings: { + content: { + src: 'https://www.youtube.com/watch?v=JbIMrJKW5N0' + subtitle: 'Learn more about AVM' + title: 'Azure Verified Modules (AVM) introduction' + } + } + type: 'Extension/HubsExtension/PartType/VideoPart' + } + position: { + colSpan: 6 + rowSpan: 4 + x: 0 + y: 0 + } + } + { + metadata: { + inputs: [] + type: 'Extension/Microsoft_AAD_IAM/PartType/UserManagementSummaryPart' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 6 + y: 0 + } + } + { + metadata: { + inputs: [] + settings: { + content: {} + } + type: 'Extension/HubsExtension/PartType/ClockPart' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 8 + y: 0 + } + } + { + metadata: { + inputs: [ + { + isOptional: true + name: 'selectedMenuItemId' + } + ] + type: 'Extension/HubsExtension/PartType/GalleryTile' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 6 + y: 2 + } + } + { + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/HelpAndSupportPart' + } + position: { + colSpan: 2 + rowSpan: 2 + x: 8 + y: 2 + } + } + ] + } +] +param location = '' +param metadata = { + model: { + filterLocale: { + value: 'en-us' + } + filters: { + value: { + MsPortalFx_TimeRange: { + displayCache: { + name: 'UTC Time' + value: 'Past 24 hours' + } + filteredPartIds: [ + 'StartboardPart-MonitorChartPart-f6c2e060-fabc-4ce5-b031-45f3296510dd' + ] + model: { + format: 'utc' + granularity: 'auto' + relative: '24h' + } + } + } + } + timeRange: { + type: 'MsPortalFx.Composition.Configuration.ValueTypes.TimeRange' + value: { + relative: { + duration: 24 + timeUnit: 1 + } + } + } + } +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -796,6 +1097,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/power-bi-dedicated/capacity/README.md b/avm/res/power-bi-dedicated/capacity/README.md index 0ef1e8e8f4..c2f1039aab 100644 --- a/avm/res/power-bi-dedicated/capacity/README.md +++ b/avm/res/power-bi-dedicated/capacity/README.md @@ -62,7 +62,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -94,6 +94,28 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/power-bi-dedicated/capacity:' + +// Required parameters +param members = [ + '' +] +param name = 'pbdcapmin001' +param sku = { + capacity: 1 +} +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -155,7 +177,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -224,6 +246,57 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/power-bi-dedicated/capacity:' + +// Required parameters +param members = [ + '' +] +param name = 'pbdcapmax001' +param sku = { + capacity: 1 + name: 'A1' + tier: 'PBIE_Azure' +} +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param mode = 'Gen2' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 Well-Architected Framework. @@ -265,7 +338,7 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -310,6 +383,37 @@ module capacity 'br/public:avm/res/power-bi-dedicated/capacity:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/power-bi-dedicated/capacity:' + +// Required parameters +param members = [ + '' +] +param name = 'pbdcapwaf001' +param sku = { + capacity: 1 +} +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -478,6 +582,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Log Analytics Contributor'` + - `'Log Analytics Reader'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/purview/account/README.md b/avm/res/purview/account/README.md index 26ccfdb7d2..7585844571 100644 --- a/avm/res/purview/account/README.md +++ b/avm/res/purview/account/README.md @@ -60,7 +60,7 @@ module account 'br/public:avm/res/purview/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,22 @@ module account 'br/public:avm/res/purview/account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/purview/account:' + +// Required parameters +param name = 'pvamin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -267,7 +283,7 @@ module account 'br/public:avm/res/purview/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -472,6 +488,181 @@ module account 'br/public:avm/res/purview/account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/purview/account:' + +// Required parameters +param name = 'pvamax001' +// Non-required parameters +param accountPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'account' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventHubPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param managedResourceGroupName = 'pvamax001-managed-rg' +param portalPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'portal' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '8372742c-408e-4a8a-a748-aca787a0e33e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param storageBlobPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param storageQueuePrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param tags = { + 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. @@ -578,7 +769,7 @@ module account 'br/public:avm/res/purview/account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -698,6 +889,102 @@ module account 'br/public:avm/res/purview/account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/purview/account:' + +// Required parameters +param name = 'pvawaf001' +// Non-required parameters +param accountPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'account' + subnetResourceId: '' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param eventHubPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + } +] +param location = '' +param managedResourceGroupName = 'pvawaf001-managed-rg' +param portalPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'portal' + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param storageBlobPrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } +] +param storageQueuePrivateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2165,6 +2452,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2546,6 +2839,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2941,6 +3240,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/recovery-services/vault/README.md b/avm/res/recovery-services/vault/README.md index b6ca61f7e5..65477a4986 100644 --- a/avm/res/recovery-services/vault/README.md +++ b/avm/res/recovery-services/vault/README.md @@ -83,7 +83,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -121,6 +121,34 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = 'rsvmin001' +// Non-required parameters +param location = '' +param replicationAlertSettings = { + customEmailAddresses: [ + 'test.user@testcompany.com' + ] + locale: 'en-US' + sendToOwners: 'Send' +} +param securitySettings = { + immutabilitySettings: { + state: 'Unlocked' + } +} +``` + +
    +

    + ### Example 2: _Test case for disaster recovery enabled_ This instance deploys the module with disaster recovery enabled. @@ -207,7 +235,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -295,6 +323,82 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = '' +// Non-required parameters +param location = '' +param replicationFabrics = [ + { + location: 'NorthEurope' + replicationContainers: [ + { + name: 'ne-container1' + replicationContainerMappings: [ + { + policyName: 'Default_values' + targetContainerName: 'pluto' + targetProtectionContainerId: '' + } + ] + } + { + name: 'ne-container2' + replicationContainerMappings: [ + { + policyName: 'Default_values' + targetContainerFabricName: 'WE-2' + targetContainerName: 'we-container1' + } + ] + } + ] + } + { + location: 'WestEurope' + name: 'WE-2' + replicationContainers: [ + { + name: 'we-container1' + replicationContainerMappings: [ + { + policyName: 'Default_values' + targetContainerFabricName: 'NorthEurope' + targetContainerName: 'ne-container2' + } + ] + } + ] + } +] +param replicationPolicies = [ + { + name: 'Default_values' + } + { + appConsistentFrequencyInMinutes: 240 + crashConsistentFrequencyInMinutes: 7 + multiVmSyncStatus: 'Disable' + name: 'Custom_values' + recoveryPointHistory: 2880 + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -686,7 +790,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1097,6 +1201,387 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = 'rsvmax001' +// Non-required parameters +param backupConfig = { + enhancedSecurityState: 'Disabled' + softDeleteFeatureState: 'Disabled' +} +param backupPolicies = [ + { + name: 'VMpolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + instantRpRetentionRangeInDays: 2 + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 180 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + } + } + { + name: 'sqlpolicy' + properties: { + backupManagementType: 'AzureWorkload' + protectedItemsCount: 0 + settings: { + isCompression: true + issqlcompression: true + timeZone: 'UTC' + } + subProtectionPolicy: [ + { + policyType: 'Full' + retentionPolicy: { + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 104 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Sunday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2019-11-07T22:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Differential' + retentionPolicy: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Monday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2017-03-07T02:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Log' + retentionPolicy: { + retentionDuration: { + count: 15 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + scheduleFrequencyInMins: 120 + schedulePolicyType: 'LogSchedulePolicy' + } + } + ] + workLoadType: 'SQLDataBase' + } + } + { + name: 'filesharepolicy' + properties: { + backupManagementType: 'AzureStorage' + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T04:30:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T04:30:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + workloadType: 'AzureFileShare' + } + } +] +param backupStorageConfig = { + crossRegionRestoreFlag: true + storageModelType: 'GeoRedundant' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param monitoringSettings = { + azureMonitorAlertSettings: { + alertsForAllJobFailures: 'Enabled' + } + classicAlertSettings: { + alertsForCriticalOperations: 'Enabled' + } +} +param privateEndpoints = [ + { + ipConfigurations: [ + { + name: 'myIpConfig-1' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-tel1' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-2' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-prot2' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'myIPconfig-3' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-srs1' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'myIPconfig-4' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-rcm1' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'myIPconfig-5' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-id1' + privateIPAddress: '10.0.0.14' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param replicationAlertSettings = { + customEmailAddresses: [ + 'test.user@testcompany.com' + ] + locale: 'en-US' + sendToOwners: 'Send' +} +param roleAssignments = [ + { + name: '35288372-e6b4-4333-9ee6-dd997b96d52b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securitySettings = { + immutabilitySettings: { + state: 'Unlocked' + } +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1469,7 +1954,7 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1859,6 +2344,368 @@ module vault 'br/public:avm/res/recovery-services/vault:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/recovery-services/vault:' + +// Required parameters +param name = 'rsvwaf001' +// Non-required parameters +param backupConfig = { + enhancedSecurityState: 'Disabled' + softDeleteFeatureState: 'Disabled' +} +param backupPolicies = [ + { + name: 'VMpolicy' + properties: { + backupManagementType: 'AzureIaasVM' + instantRPDetails: {} + instantRpRetentionRangeInDays: 2 + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 180 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 12 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T07:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T07:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + } + } + { + name: 'sqlpolicy' + properties: { + backupManagementType: 'AzureWorkload' + protectedItemsCount: 0 + settings: { + isCompression: true + issqlcompression: true + timeZone: 'UTC' + } + subProtectionPolicy: [ + { + policyType: 'Full' + retentionPolicy: { + monthlySchedule: { + retentionDuration: { + count: 60 + durationType: 'Months' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + weeklySchedule: { + daysOfTheWeek: [ + 'Sunday' + ] + retentionDuration: { + count: 104 + durationType: 'Weeks' + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + yearlySchedule: { + monthsOfYear: [ + 'January' + ] + retentionDuration: { + count: 10 + durationType: 'Years' + } + retentionScheduleFormatType: 'Weekly' + retentionScheduleWeekly: { + daysOfTheWeek: [ + 'Sunday' + ] + weeksOfTheMonth: [ + 'First' + ] + } + retentionTimes: [ + '2019-11-07T22:00:00Z' + ] + } + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Sunday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2019-11-07T22:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Differential' + retentionPolicy: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunDays: [ + 'Monday' + ] + scheduleRunFrequency: 'Weekly' + scheduleRunTimes: [ + '2017-03-07T02:00:00Z' + ] + scheduleWeeklyFrequency: 0 + } + } + { + policyType: 'Log' + retentionPolicy: { + retentionDuration: { + count: 15 + durationType: 'Days' + } + retentionPolicyType: 'SimpleRetentionPolicy' + } + schedulePolicy: { + scheduleFrequencyInMins: 120 + schedulePolicyType: 'LogSchedulePolicy' + } + } + ] + workLoadType: 'SQLDataBase' + } + } + { + name: 'filesharepolicy' + properties: { + backupManagementType: 'AzureStorage' + protectedItemsCount: 0 + retentionPolicy: { + dailySchedule: { + retentionDuration: { + count: 30 + durationType: 'Days' + } + retentionTimes: [ + '2019-11-07T04:30:00Z' + ] + } + retentionPolicyType: 'LongTermRetentionPolicy' + } + schedulePolicy: { + schedulePolicyType: 'SimpleSchedulePolicy' + scheduleRunFrequency: 'Daily' + scheduleRunTimes: [ + '2019-11-07T04:30:00Z' + ] + scheduleWeeklyFrequency: 0 + } + timeZone: 'UTC' + workloadType: 'AzureFileShare' + } + } +] +param backupStorageConfig = { + crossRegionRestoreFlag: true + storageModelType: 'GeoRedundant' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param monitoringSettings = { + azureMonitorAlertSettings: { + alertsForAllJobFailures: 'Enabled' + } + classicAlertSettings: { + alertsForCriticalOperations: 'Enabled' + } +} +param privateEndpoints = [ + { + ipConfigurations: [ + { + name: 'myIpConfig-1' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-tel1' + privateIPAddress: '10.0.0.10' + } + } + { + name: 'myIPconfig-2' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-prot2' + privateIPAddress: '10.0.0.11' + } + } + { + name: 'myIPconfig-3' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-srs1' + privateIPAddress: '10.0.0.12' + } + } + { + name: 'myIPconfig-4' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-rcm1' + privateIPAddress: '10.0.0.13' + } + } + { + name: 'myIPconfig-5' + properties: { + groupId: 'AzureSiteRecovery' + memberName: 'SiteRecovery-id1' + privateIPAddress: '10.0.0.14' + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param replicationAlertSettings = { + customEmailAddresses: [ + 'test.user@testcompany.com' + ] + locale: 'en-US' + sendToOwners: 'Send' +} +param securitySettings = { + immutabilitySettings: { + state: 'Unlocked' + } +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2445,6 +3292,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2603,6 +3461,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Backup Contributor'` + - `'Backup Operator'` + - `'Backup Reader'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Site Recovery Contributor'` + - `'Site Recovery Operator'` + - `'Site Recovery Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/relay/namespace/README.md b/avm/res/relay/namespace/README.md index 837fa1fa43..4059dd7c06 100644 --- a/avm/res/relay/namespace/README.md +++ b/avm/res/relay/namespace/README.md @@ -71,7 +71,7 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -93,6 +93,22 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/relay/namespace:' + +// Required parameters +param name = 'rnmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -255,7 +271,7 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -433,6 +449,158 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/relay/namespace:' + +// Required parameters +param name = 'rnmax001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param hybridConnections = [ + { + name: 'rnmaxhc001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + userMetadata: '[{\'key\':\'endpoint\',\'value\':\'db-server.constoso.com:1433\'}]' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + subnet: { + id: '' + ignoreMissingVnetServiceEndpoint: true + } + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'd3dff05a-96d7-4d63-82c2-0fd8ac7b859d' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Standard' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param wcfRelays = [ + { + name: 'rnmaxwcf001' + relayType: 'NetTcp' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + ] + } +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -541,7 +709,7 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -659,6 +827,104 @@ module namespace 'br/public:avm/res/relay/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/relay/namespace:' + +// Required parameters +param name = 'rnwaf001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param hybridConnections = [ + { + name: 'rnwafhc001' + userMetadata: '[{\'key\':\'endpoint\',\'value\':\'db-server.constoso.com:1433\'}]' + } +] +param location = '' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + subnet: { + id: '' + ignoreMissingVnetServiceEndpoint: true + } + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param wcfRelays = [ + { + name: 'rnwafwcf001' + relayType: 'NetTcp' + } +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -1215,6 +1481,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1326,6 +1603,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Relay Listener'` + - `'Azure Relay Owner'` + - `'Azure Relay Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/relay/namespace/hybrid-connection/README.md b/avm/res/relay/namespace/hybrid-connection/README.md index 96212178af..8df88f210d 100644 --- a/avm/res/relay/namespace/hybrid-connection/README.md +++ b/avm/res/relay/namespace/hybrid-connection/README.md @@ -144,6 +144,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Relay Listener'` + - `'Azure Relay Owner'` + - `'Azure Relay Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/relay/namespace/wcf-relay/README.md b/avm/res/relay/namespace/wcf-relay/README.md index abc0f0c610..80caef4d77 100644 --- a/avm/res/relay/namespace/wcf-relay/README.md +++ b/avm/res/relay/namespace/wcf-relay/README.md @@ -161,6 +161,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Relay Listener'` + - `'Azure Relay Owner'` + - `'Azure Relay Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/resource-graph/query/README.md b/avm/res/resource-graph/query/README.md index fd64204c24..a77e9f432a 100644 --- a/avm/res/resource-graph/query/README.md +++ b/avm/res/resource-graph/query/README.md @@ -57,7 +57,7 @@ module query 'br/public:avm/res/resource-graph/query:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -82,6 +82,23 @@ module query 'br/public:avm/res/resource-graph/query:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resource-graph/query:' + +// Required parameters +param name = 'rdsmin001' +param query = 'Resources | limit 10' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -137,7 +154,7 @@ module query 'br/public:avm/res/resource-graph/query:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -198,6 +215,51 @@ module query 'br/public:avm/res/resource-graph/query:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resource-graph/query:' + +// Required parameters +param name = 'rdsmax001' +param query = '' +// Non-required parameters +param location = '' +param lock = { + kind: 'None' +} +param queryDescription = 'An example query to list first 5 subscriptions.' +param roleAssignments = [ + { + name: '9634350c-b241-4481-8c22-4166891596ab' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 Well-Architected Framework. @@ -234,7 +296,7 @@ module query 'br/public:avm/res/resource-graph/query:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -274,6 +336,32 @@ module query 'br/public:avm/res/resource-graph/query:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resource-graph/query:' + +// Required parameters +param name = 'rdswaf001' +param query = 'resourcecontainers| where type == \'microsoft.resources/subscriptions\' | take 5' +// Non-required parameters +param location = '' +param lock = { + kind: 'None' +} +param queryDescription = 'An example query to list first 5 subscriptions.' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -374,6 +462,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/resources/deployment-script/README.md b/avm/res/resources/deployment-script/README.md index 9dac2f308c..6cb35243e4 100644 --- a/avm/res/resources/deployment-script/README.md +++ b/avm/res/resources/deployment-script/README.md @@ -76,7 +76,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -128,6 +128,38 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdscli001' +// Non-required parameters +param azCliVersion = '2.9.1' +param environmentVariables = [ + { + name: 'var1' + value: 'AVM Deployment Script test!' + } +] +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param scriptContent = 'echo \'Enviornment variable value is: \' $var1' +param storageAccountResourceId = '' +``` + +
    +

    + ### Example 2: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -162,7 +194,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -200,6 +232,30 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzurePowerShell' +param name = 'rdsmin001' +// Non-required parameters +param azPowerShellVersion = '9.7' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param scriptContent = 'Write-Host \'AVM Deployment Script test!\'' +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -278,7 +334,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -382,6 +438,74 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdsmax001' +// Non-required parameters +param arguments = '-argument1 \\\'test\\\'' +param azCliVersion = '2.9.1' +param cleanupPreference = 'Always' +param containerGroupName = 'dep-cg-rdsmax' +param environmentVariables = [ + { + name: 'var1' + value: 'test' + } + { + name: 'var2' + secureValue: '' + } +] +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param roleAssignments = [ + { + name: 'd8eadbae-2c20-4e8f-9a48-4c6d739d0c4a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param timeout = 'PT1H' +``` + +
    +

    + ### Example 4: _Using Private Endpoint_ This instance deploys the module with access to a private endpoint. @@ -424,7 +548,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -482,6 +606,38 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdspe001' +// Non-required parameters +param azCliVersion = '2.9.1' +param cleanupPreference = 'Always' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param subnetResourceIds = [ + '' +] +param timeout = 'PT1H' +``` + +
    +

    + ### Example 5: _Using Private Networking_ This instance deploys the module with access to a private network. @@ -524,7 +680,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -582,6 +738,38 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdsnet001' +// Non-required parameters +param azCliVersion = '2.9.1' +param cleanupPreference = 'Always' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param subnetResourceIds = [ + '' +] +param timeout = 'PT1H' +``` + +
    +

    + ### Example 6: _Using Azure PowerShell_ This instance deploys the module with an Azure PowerShell script. @@ -619,7 +807,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -666,6 +854,33 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzurePowerShell' +param name = 'rdsps001' +// Non-required parameters +param arguments = '-var1 \\\'AVM Deployment Script test!\\\'' +param azPowerShellVersion = '9.7' +param location = '' +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param scriptContent = 'param([string] $var1);Write-Host \'Argument var1 value is:\' $var1' +param storageAccountResourceId = '' +``` + +
    +

    + ### Example 7: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -713,7 +928,7 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    -via JSON Parameter file +via JSON parameters file ```json { @@ -778,6 +993,43 @@ module deploymentScript 'br/public:avm/res/resources/deployment-script:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/deployment-script:' + +// Required parameters +param kind = 'AzureCLI' +param name = 'rdswaf001' +// Non-required parameters +param azCliVersion = '2.9.1' +param cleanupPreference = 'Always' +param location = '' +param lock = { + kind: 'None' +} +param managedIdentities = { + userAssignedResourcesIds: [ + '' + ] +} +param retentionInterval = 'P1D' +param runOnce = true +param scriptContent = 'echo \'AVM Deployment Script test!\'' +param storageAccountResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param timeout = 'PT1H' +``` + +
    +

    + ## Parameters **Required parameters** @@ -1012,6 +1264,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/resources/resource-group/README.md b/avm/res/resources/resource-group/README.md index bf87e88b4c..f2908dcd05 100644 --- a/avm/res/resources/resource-group/README.md +++ b/avm/res/resources/resource-group/README.md @@ -56,7 +56,7 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -78,6 +78,22 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +// Required parameters +param name = 'avm-resources.resourcegroups-rrgmin-rg' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -132,7 +148,7 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +204,50 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +// Required parameters +param name = 'avm-resources.resourcegroups-rrgmax-rg' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '3566ddd3-870d-4618-bd22-3d50915a21ef' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 Well-Architected Framework. @@ -223,7 +283,7 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -258,6 +318,31 @@ module resourceGroup 'br/public:avm/res/resources/resource-group:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/resources/resource-group:' + +// Required parameters +param name = 'avm-resources.resourcegroups-rrgwaf-rg' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index a0de84e740..056c76fef4 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -18,6 +18,7 @@ This module deploys a Search Service. | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Search/searchServices` | [2024-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Search/2024-03-01-preview/searchServices) | @@ -32,9 +33,10 @@ The following section provides usage examples for the module, which were used to >**Note**: To reference the module, please use the following syntax `br/public:avm/res/search/search-service:`. - [Using only defaults](#example-1-using-only-defaults) -- [Using large parameter set](#example-2-using-large-parameter-set) -- [Private endpoint-enabled deployment](#example-3-private-endpoint-enabled-deployment) -- [WAF-aligned](#example-4-waf-aligned) +- [Deploying with a key vault reference to save secrets](#example-2-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [Private endpoint-enabled deployment](#example-4-private-endpoint-enabled-deployment) +- [WAF-aligned](#example-5-waf-aligned) ### Example 1: _Using only defaults_ @@ -62,7 +64,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,7 +86,126 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -### Example 2: _Using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'sssmin002' +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 2: _Deploying with a key vault reference to save secrets_ + +This instance deploys the module saving admin key secrets in a key vault. + + +

    + +via Bicep module + +```bicep +module searchService 'br/public:avm/res/search/search-service:' = { + name: 'searchServiceDeployment' + params: { + // Required parameters + name: 'kv-ref' + // Non-required parameters + authOptions: { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } + } + disableLocalAuth: false + location: '' + secretsExportConfiguration: { + keyVaultResourceId: '' + primaryAdminKeyName: 'Primary-Admin-Key' + secondaryAdminKeyName: 'Secondary-Admin-Key' + } + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "kv-ref" + }, + // Non-required parameters + "authOptions": { + "value": { + "aadOrApiKey": { + "aadAuthFailureMode": "http401WithBearerChallenge" + } + } + }, + "disableLocalAuth": { + "value": false + }, + "location": { + "value": "" + }, + "secretsExportConfiguration": { + "value": { + "keyVaultResourceId": "", + "primaryAdminKeyName": "Primary-Admin-Key", + "secondaryAdminKeyName": "Secondary-Admin-Key" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'kv-ref' +// Non-required parameters +param authOptions = { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } +} +param disableLocalAuth = false +param location = '' +param secretsExportConfiguration = { + keyVaultResourceId: '' + primaryAdminKeyName: 'Primary-Admin-Key' + secondaryAdminKeyName: 'Secondary-Admin-Key' +} +``` + +
    +

    + +### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -180,7 +301,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -300,7 +421,93 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -### Example 3: _Private endpoint-enabled deployment_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'sssmax001' +// Non-required parameters +param authOptions = { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } +} +param cmkEnforcement = 'Enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = false +param hostingMode = 'highDensity' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param networkRuleSet = { + ipRules: [ + { + value: '40.74.28.0/23' + } + { + value: '87.147.204.13' + } + ] +} +param partitionCount = 2 +param replicaCount = 3 +param roleAssignments = [ + { + name: '73ec30e0-2e25-475f-beec-d90cab332eb7' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param semanticSearch = 'standard' +param sku = 'standard3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + +### Example 4: _Private endpoint-enabled deployment_ This instance deploys the module with private endpoints. @@ -314,7 +521,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { name: 'searchServiceDeployment' params: { // Required parameters - name: 'ssspe001' + name: 'ssspr001' // Non-required parameters location: '' privateEndpoints: [ @@ -374,7 +581,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -383,7 +590,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { "parameters": { // Required parameters "name": { - "value": "ssspe001" + "value": "ssspr001" }, // Non-required parameters "location": { @@ -452,7 +659,71 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -### Example 4: _WAF-aligned_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'ssspr001' +// Non-required parameters +param location = '' +param privateEndpoints = [ + { + applicationSecurityGroupResourceIds: [ + '' + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param sharedPrivateLinkResources = [ + { + groupId: 'blob' + privateLinkResourceId: '' + requestMessage: 'Please approve this request' + resourceRegion: '' + } + { + groupId: 'vault' + privateLinkResourceId: '' + requestMessage: 'Please approve this request' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + +### Example 5: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -525,7 +796,7 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -618,6 +889,69 @@ module searchService 'br/public:avm/res/search/search-service:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/search/search-service:' + +// Required parameters +param name = 'ssswaf001' +// Non-required parameters +param authOptions = { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } +} +param cmkEnforcement = 'Enabled' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = false +param hostingMode = 'highDensity' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param networkRuleSet = { + ipRules: [ + { + value: '40.74.28.0/23' + } + { + value: '87.147.204.13' + } + ] +} +param partitionCount = 2 +param replicaCount = 3 +param sku = 'standard3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -645,6 +979,7 @@ module searchService 'br/public:avm/res/search/search-service:' = { | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method. | | [`replicaCount`](#parameter-replicacount) | int | The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | | [`semanticSearch`](#parameter-semanticsearch) | string | Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. | | [`sharedPrivateLinkResources`](#parameter-sharedprivatelinkresources) | array | The sharedPrivateLinkResources to create as part of the search Service. | | [`sku`](#parameter-sku) | string | Defines the SKU of an Azure Cognitive Search Service, which determines price tier and capacity limits. | @@ -1236,6 +1571,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1370,6 +1716,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'Search Index Data Contributor'` + - `'Search Index Data Reader'` + - `'Search Service Contributor'` + - `'User Access Administrator'` **Required parameters** @@ -1461,6 +1816,47 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultResourceId`](#parameter-secretsexportconfigurationkeyvaultresourceid) | string | The key vault name where to store the API Admin keys generated by the modules. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`primaryAdminKeyName`](#parameter-secretsexportconfigurationprimaryadminkeyname) | string | The primaryAdminKey secret name to create. | +| [`secondaryAdminKeyName`](#parameter-secretsexportconfigurationsecondaryadminkeyname) | string | The secondaryAdminKey secret name to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The key vault name where to store the API Admin keys generated by the modules. + +- Required: Yes +- Type: string + +### Parameter: `secretsExportConfiguration.primaryAdminKeyName` + +The primaryAdminKey secret name to create. + +- Required: No +- Type: string + +### Parameter: `secretsExportConfiguration.secondaryAdminKeyName` + +The secondaryAdminKey secret name to create. + +- Required: No +- Type: string + ### Parameter: `semanticSearch` Sets options that control the availability of semantic search. This configuration is only possible for certain search SKUs in certain locations. @@ -1515,9 +1911,9 @@ Tags to help categorize the resource in the Azure portal. | Output | Type | Description | | :-- | :-- | :-- | +| `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the search service. | -| `privateEndpoints` | array | The private endpoints of the search service. | | `resourceGroupName` | string | The name of the resource group the search service was created in. | | `resourceId` | string | The resource ID of the search service. | | `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | diff --git a/avm/res/search/search-service/main.bicep b/avm/res/search/search-service/main.bicep index 951adfe725..df608c8af6 100644 --- a/avm/res/search/search-service/main.bicep +++ b/avm/res/search/search-service/main.bicep @@ -60,6 +60,9 @@ param sharedPrivateLinkResources array = [] ]) param publicNetworkAccess string = 'Enabled' +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + @description('Optional. The number of replicas in the search service. If specified, it must be a value between 1 and 12 inclusive for standard SKUs or between 1 and 3 inclusive for basic SKU.') @minValue(1) @maxValue(12) @@ -324,6 +327,36 @@ module searchService_sharedPrivateLinkResources 'shared-private-link-resource/ma } ] +module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name, location)}-secrets-kv' + scope: resourceGroup( + split((secretsExportConfiguration.?keyVaultResourceId ?? '//'), '/')[2], + split((secretsExportConfiguration.?keyVaultResourceId ?? '////'), '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId ?? '//', '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'primaryAdminKeyName') + ? [ + { + name: secretsExportConfiguration!.primaryAdminKeyName + value: searchService.listAdminKeys().primaryKey + } + ] + : [], + contains(secretsExportConfiguration!, 'secondaryAdminKeyName') + ? [ + { + name: secretsExportConfiguration!.secondaryAdminKeyName + value: searchService.listAdminKeys().secondaryKey + } + ] + : [] + ) + } +} + // =========== // // Outputs // // =========== // @@ -343,16 +376,10 @@ output systemAssignedMIPrincipalId string = searchService.?identity.?principalId @description('The location the resource was deployed into.') output location string = searchService.location -@description('The private endpoints of the search service.') -output privateEndpoints array = [ - for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { - name: searchService_privateEndpoints[i].outputs.name - resourceId: searchService_privateEndpoints[i].outputs.resourceId - groupId: searchService_privateEndpoints[i].outputs.groupId - customDnsConfig: searchService_privateEndpoints[i].outputs.customDnsConfig - networkInterfaceIds: searchService_privateEndpoints[i].outputs.networkInterfaceIds - } -] +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} // =============== // // Definitions // @@ -530,3 +557,20 @@ 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 secretsExportConfigurationType = { + @description('Required. The key vault name where to store the API Admin keys generated by the modules.') + keyVaultResourceId: string + + @description('Optional. The primaryAdminKey secret name to create.') + primaryAdminKeyName: string? + + @description('Optional. The secondaryAdminKey secret name to create.') + secondaryAdminKeyName: string? +} + +import { secretSetType } from 'modules/keyVaultExport.bicep' +type secretsOutputType = { + @description('An exported secret\'s references.') + *: secretSetType +} diff --git a/avm/res/search/search-service/main.json b/avm/res/search/search-service/main.json index c4b625ff47..24719a5ca7 100644 --- a/avm/res/search/search-service/main.json +++ b/avm/res/search/search-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8483667347070963331" + "version": "0.30.23.60470", + "templateHash": "13527260085574333800" }, "name": "Search Services", "description": "This module deploys a Search Service.", @@ -473,6 +473,63 @@ } }, "nullable": true + }, + "secretsExportConfigurationType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The key vault name where to store the API Admin keys generated by the modules." + } + }, + "primaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAdminKey secret name to create." + } + }, + "secondaryAdminKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAdminKey secret name to create." + } + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/secretSetType", + "metadata": { + "description": "An exported secret's references." + } + } + }, + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "modules/keyVaultExport.bicep" + } + } } }, "parameters": { @@ -579,6 +636,13 @@ "description": "Optional. This value can be set to 'Enabled' to avoid breaking changes on existing customer resources and templates. If set to 'Disabled', traffic over public interface is not allowed, and private endpoint connections would be the exclusive access method." } }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, "replicaCount": { "type": "int", "defaultValue": 3, @@ -1593,8 +1657,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2330033720810948871" + "version": "0.30.23.60470", + "templateHash": "1073269867332822875" }, "name": "Search Services Private Link Resources", "description": "This module deploys a Search Service Private Link Resource.", @@ -1689,6 +1753,140 @@ "dependsOn": [ "searchService" ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", + "subscriptionId": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '////'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAdminKeyName'), createArray(createObject('name', parameters('secretsExportConfiguration').primaryAdminKeyName, 'value', listAdminKeys(resourceId('Microsoft.Search/searchServices', parameters('name')), '2024-03-01-preview').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAdminKeyName'), createArray(createObject('name', parameters('secretsExportConfiguration').secondaryAdminKeyName, 'value', listAdminKeys(resourceId('Microsoft.Search/searchServices', parameters('name')), '2024-03-01-preview').secondaryKey)), createArray()))]" + } + }, + "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.30.23.60470", + "templateHash": "12263717469683062316" + } + }, + "definitions": { + "secretSetType": { + "type": "object", + "properties": { + "secretResourceId": { + "type": "string", + "metadata": { + "description": "The resourceId of the exported secret." + } + }, + "secretUri": { + "type": "string", + "metadata": { + "description": "The secret URI of the exported secret." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "secretToSetType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret to set." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret to set." + } + } + } + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the Key Vault to set the ecrets in." + } + }, + "secretsToSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretToSetType" + }, + "metadata": { + "description": "Required. The secrets to set in the Key Vault." + } + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secrets": { + "copy": { + "name": "secrets", + "count": "[length(parameters('secretsToSet'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", + "properties": { + "value": "[parameters('secretsToSet')[copyIndex()].value]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetType" + }, + "metadata": { + "description": "The references to the secrets exported to the provided Key Vault." + }, + "copy": { + "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", + "input": { + "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", + "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" + } + } + } + } + } + }, + "dependsOn": [ + "searchService" + ] } }, "outputs": { @@ -1727,21 +1925,12 @@ }, "value": "[reference('searchService', '2024-03-01-preview', 'full').location]" }, - "privateEndpoints": { - "type": "array", + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", "metadata": { - "description": "The private endpoints of the search service." + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, - "copy": { - "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", - "input": { - "name": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", - "customDnsConfig": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", - "networkInterfaceIds": "[reference(format('searchService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" - } - } + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" } } } \ No newline at end of file diff --git a/avm/res/search/search-service/modules/keyVaultExport.bicep b/avm/res/search/search-service/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..d537d2407e --- /dev/null +++ b/avm/res/search/search-service/modules/keyVaultExport.bicep @@ -0,0 +1,62 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the ecrets in.') +param keyVaultName string + +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetType[] = [ + #disable-next-line outputs-should-not-contain-secrets // Only returning the references, not a secret value + for index in range(0, length(secretsToSet ?? [])): { + secretResourceId: secrets[index].id + secretUri: secrets[index].properties.secretUri + } +] + +// =============== // +// Definitions // +// =============== // + +@export() +type secretSetType = { + @description('The resourceId of the exported secret.') + secretResourceId: string + + @description('The secret URI of the exported secret.') + secretUri: string +} + +type secretToSetType = { + @description('Required. The name of the secret to set.') + name: string + + @description('Required. The value of the secret to set.') + @secure() + value: string +} diff --git a/avm/res/search/search-service/tests/e2e/kvSecrets/dependencies.bicep b/avm/res/search/search-service/tests/e2e/kvSecrets/dependencies.bicep new file mode 100644 index 0000000000..da0b29e26f --- /dev/null +++ b/avm/res/search/search-service/tests/e2e/kvSecrets/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + enableRbacAuthorization: true + tenantId: subscription().tenantId + } +} + +@description('The key vault id of the Key Vault created.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep b/avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep new file mode 100644 index 0000000000..cdd93d36cd --- /dev/null +++ b/avm/res/search/search-service/tests/e2e/kvSecrets/main.test.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving admin key secrets in a key vault.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-search.searchservices-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssskvs' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============== // +// General resources +// ============== // +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + location: resourceLocation + name: '${namePrefix}-kv-ref' + disableLocalAuth: false + authOptions: { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } + } + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + primaryAdminKeyName: 'Primary-Admin-Key' + secondaryAdminKeyName: 'Secondary-Admin-Key' + } + } +} diff --git a/avm/res/search/search-service/tests/e2e/pe/main.test.bicep b/avm/res/search/search-service/tests/e2e/pe/main.test.bicep index 185cd85d5f..76fecb0274 100644 --- a/avm/res/search/search-service/tests/e2e/pe/main.test.bicep +++ b/avm/res/search/search-service/tests/e2e/pe/main.test.bicep @@ -15,7 +15,7 @@ param resourceGroupName string = 'dep-${namePrefix}-search.searchservices-${serv 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 = 'ssspe' +param serviceShort string = 'ssspr' @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' diff --git a/avm/res/service-bus/namespace/README.md b/avm/res/service-bus/namespace/README.md index 6cee870109..bce7d6853c 100644 --- a/avm/res/service-bus/namespace/README.md +++ b/avm/res/service-bus/namespace/README.md @@ -59,11 +59,12 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { params: { // Required parameters name: 'sbnmin001' - skuObject: { - name: 'Basic' - } // Non-required parameters location: '' + skuObject: { + capacity: 2 + name: 'Premium' + } } } ``` @@ -73,7 +74,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,14 +85,15 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "name": { "value": "sbnmin001" }, - "skuObject": { - "value": { - "name": "Basic" - } - }, // Non-required parameters "location": { "value": "" + }, + "skuObject": { + "value": { + "capacity": 2, + "name": "Premium" + } } } } @@ -100,6 +102,26 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnmin001' +// Non-required parameters +param location = '' +param skuObject = { + capacity: 2 + name: 'Premium' +} +``` + +
    +

    + ### Example 2: _Using encryption parameter set_ This instance deploys the module with features enabled for CMK encryption. @@ -115,10 +137,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { params: { // Required parameters name: 'sbnencr001' - skuObject: { - capacity: 1 - name: 'Premium' - } // Non-required parameters customerManagedKey: { keyName: '' @@ -132,6 +150,10 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { '' ] } + skuObject: { + capacity: 1 + name: 'Premium' + } } } ``` @@ -141,7 +163,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -152,12 +174,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "name": { "value": "sbnencr001" }, - "skuObject": { - "value": { - "capacity": 1, - "name": "Premium" - } - }, // Non-required parameters "customerManagedKey": { "value": { @@ -176,6 +192,12 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "" ] } + }, + "skuObject": { + "value": { + "capacity": 1, + "name": "Premium" + } } } } @@ -184,6 +206,37 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnencr001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: false + userAssignedResourcesIds: [ + '' + ] +} +param skuObject = { + capacity: 1 + name: 'Premium' +} +``` + +
    +

    + ### Example 3: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -199,10 +252,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { params: { // Required parameters name: 'sbnmax001' - skuObject: { - capacity: 16 - name: 'Premium' - } // Non-required parameters authorizationRules: [ { @@ -382,6 +431,10 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { roleDefinitionIdOrName: '' } ] + skuObject: { + capacity: 16 + name: 'Premium' + } tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -431,7 +484,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { ] } ] - zoneRedundant: true } } ``` @@ -441,7 +493,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -452,12 +504,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "name": { "value": "sbnmax001" }, - "skuObject": { - "value": { - "capacity": 16, - "name": "Premium" - } - }, // Non-required parameters "authorizationRules": { "value": [ @@ -663,6 +709,12 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { } ] }, + "skuObject": { + "value": { + "capacity": 16, + "name": "Premium" + } + }, "tags": { "value": { "Environment": "Non-Prod", @@ -715,9 +767,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { ] } ] - }, - "zoneRedundant": { - "value": true } } } @@ -726,6 +775,252 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnmax001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'RuntimeAuditLogs' + } + ] + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'diagnosticsetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] +} +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param premiumMessagingPartitions = 1 +param privateEndpoints = [ + { + customDnsConfigs: [ + { + fqdn: 'abc.namespace.com' + ipAddresses: [ + '10.0.0.10' + ] + } + ] + ipConfigurations: [ + { + name: 'myIPconfig' + properties: { + groupId: 'namespace' + memberName: 'namespace' + privateIPAddress: '10.0.0.10' + } + } + ] + name: 'myPrivateEndpoint' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + privateLinkServiceConnectionName: 'customLinkName' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Enabled' +param queues = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + autoDeleteOnIdle: 'PT5M' + maxMessageSizeInKilobytes: 2048 + name: 'sbnmaxq001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } +] +param roleAssignments = [ + { + name: '2c42f915-20bf-4094-ba42-fee1f811d374' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuObject = { + capacity: 16 + name: 'Premium' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + name: 'sbnmaxt001' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + subscriptions: [ + { + name: 'subscription001' + } + ] + } +] +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -741,10 +1036,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { params: { // Required parameters name: 'sbnwaf001' - skuObject: { - capacity: 2 - name: 'Premium' - } // Non-required parameters authorizationRules: [ { @@ -850,6 +1141,10 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { } ] roleAssignments: [] + skuObject: { + capacity: 2 + name: 'Premium' + } tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' @@ -878,7 +1173,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { roleAssignments: [] } ] - zoneRedundant: true } } ``` @@ -888,7 +1182,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -899,12 +1193,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "name": { "value": "sbnwaf001" }, - "skuObject": { - "value": { - "capacity": 2, - "name": "Premium" - } - }, // Non-required parameters "authorizationRules": { "value": [ @@ -1036,6 +1324,12 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "roleAssignments": { "value": [] }, + "skuObject": { + "value": { + "capacity": 2, + "name": "Premium" + } + }, "tags": { "value": { "Environment": "Non-Prod", @@ -1067,9 +1361,6 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { "roleAssignments": [] } ] - }, - "zoneRedundant": { - "value": true } } } @@ -1078,6 +1369,157 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-bus/namespace:' + +// Required parameters +param name = 'sbnwaf001' +// Non-required parameters +param authorizationRules = [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param disableLocalAuth = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourcesIds: [ + '' + ] +} +param minimumTlsVersion = '1.2' +param networkRuleSets = { + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + ipMask: '10.0.1.0/32' + } + { + action: 'Allow' + ipMask: '10.0.2.0/32' + } + ] + trustedServiceAccessEnabled: true + virtualNetworkRules: [ + { + ignoreMissingVnetServiceEndpoint: true + subnetResourceId: '' + } + ] +} +param premiumMessagingPartitions = 1 +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'namespace' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param publicNetworkAccess = 'Enabled' +param queues = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + autoDeleteOnIdle: 'PT5M' + maxMessageSizeInKilobytes: 2048 + name: 'sbnwafq001' + roleAssignments: [] + } +] +param roleAssignments = [] +param skuObject = { + capacity: 2 + name: 'Premium' +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param topics = [ + { + authorizationRules: [ + { + name: 'RootManageSharedAccessKey' + rights: [ + 'Listen' + 'Manage' + 'Send' + ] + } + { + name: 'AnotherKey' + rights: [ + 'Listen' + 'Send' + ] + } + ] + name: 'sbnwaft001' + roleAssignments: [] + } +] +``` + +
    +

    + ## Parameters **Required parameters** @@ -1085,7 +1527,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { | Parameter | Type | Description | | :-- | :-- | :-- | | [`name`](#parameter-name) | string | Name of the Service Bus Namespace. | -| [`skuObject`](#parameter-skuobject) | object | The SKU of the Service Bus Namespace. | +| [`skuObject`](#parameter-skuobject) | object | The SKU of the Service Bus Namespace. Defaulted to Premium for ZoneRedundant configurations by default. | **Optional parameters** @@ -1112,7 +1554,7 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`topics`](#parameter-topics) | array | The topics to create in the service bus namespace. | -| [`zoneRedundant`](#parameter-zoneredundant) | bool | Enabling this property creates a Premium Service Bus Namespace in regions supported availability zones. | +| [`zoneRedundant`](#parameter-zoneredundant) | bool | Enabled by default in order to align with resiliency best practices, thus requires Premium SKU. | ### Parameter: `name` @@ -1123,10 +1565,17 @@ Name of the Service Bus Namespace. ### Parameter: `skuObject` -The SKU of the Service Bus Namespace. +The SKU of the Service Bus Namespace. Defaulted to Premium for ZoneRedundant configurations by default. -- Required: Yes +- Required: No - Type: object +- Default: + ```Bicep + { + capacity: 2 + name: 'Premium' + } + ``` **Required parameters** @@ -1999,6 +2448,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -2353,6 +2813,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2479,6 +2948,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -2763,6 +3241,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** @@ -3069,11 +3556,11 @@ Value that indicates whether the topic supports ordering. ### Parameter: `zoneRedundant` -Enabling this property creates a Premium Service Bus Namespace in regions supported availability zones. +Enabled by default in order to align with resiliency best practices, thus requires Premium SKU. - Required: No - Type: bool -- Default: `False` +- Default: `True` ## Outputs diff --git a/avm/res/service-bus/namespace/main.bicep b/avm/res/service-bus/namespace/main.bicep index 08ecf97e72..7b00c06d4c 100644 --- a/avm/res/service-bus/namespace/main.bicep +++ b/avm/res/service-bus/namespace/main.bicep @@ -9,11 +9,14 @@ param name string @description('Optional. Location for all resources.') param location string = resourceGroup().location -@description('Required. The SKU of the Service Bus Namespace.') -param skuObject skuType +@description('Required. The SKU of the Service Bus Namespace. Defaulted to Premium for ZoneRedundant configurations by default.') +param skuObject skuType = { + name: 'Premium' + capacity: 2 +} -@description('Optional. Enabling this property creates a Premium Service Bus Namespace in regions supported availability zones.') -param zoneRedundant bool = false +@description('Optional. Enabled by default in order to align with resiliency best practices, thus requires Premium SKU.') +param zoneRedundant bool = true @allowed([ '1.0' diff --git a/avm/res/service-bus/namespace/main.json b/avm/res/service-bus/namespace/main.json index b3917916f0..8b30c416be 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.29.47.4906", - "templateHash": "16628890374295506516" + "templateHash": "6397771352503979306" }, "name": "Service Bus Namespaces", "description": "This module deploys a Service Bus Namespace.", @@ -1137,15 +1137,19 @@ }, "skuObject": { "$ref": "#/definitions/skuType", + "defaultValue": { + "name": "Premium", + "capacity": 2 + }, "metadata": { - "description": "Required. The SKU of the Service Bus Namespace." + "description": "Required. The SKU of the Service Bus Namespace. Defaulted to Premium for ZoneRedundant configurations by default." } }, "zoneRedundant": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { - "description": "Optional. Enabling this property creates a Premium Service Bus Namespace in regions supported availability zones." + "description": "Optional. Enabled by default in order to align with resiliency best practices, thus requires Premium SKU." } }, "minimumTlsVersion": { diff --git a/avm/res/service-bus/namespace/queue/README.md b/avm/res/service-bus/namespace/queue/README.md index cc4a9b560c..0c581d4e73 100644 --- a/avm/res/service-bus/namespace/queue/README.md +++ b/avm/res/service-bus/namespace/queue/README.md @@ -236,6 +236,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-bus/namespace/tests/e2e/defaults/main.test.bicep b/avm/res/service-bus/namespace/tests/e2e/defaults/main.test.bicep index 3d75b0c635..067d0c6f69 100644 --- a/avm/res/service-bus/namespace/tests/e2e/defaults/main.test.bicep +++ b/avm/res/service-bus/namespace/tests/e2e/defaults/main.test.bicep @@ -44,7 +44,8 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: resourceLocation skuObject: { - name: 'Basic' + name: 'Premium' + capacity: 2 } } } 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 75f7aac495..fcf8d82aee 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 @@ -76,7 +76,6 @@ module testDeployment '../../../main.bicep' = [ capacity: 16 } premiumMessagingPartitions: 1 - zoneRedundant: true tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/avm/res/service-bus/namespace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/service-bus/namespace/tests/e2e/waf-aligned/main.test.bicep index f40c29ea50..2160534080 100644 --- a/avm/res/service-bus/namespace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/service-bus/namespace/tests/e2e/waf-aligned/main.test.bicep @@ -76,7 +76,6 @@ module testDeployment '../../../main.bicep' = [ capacity: 2 } premiumMessagingPartitions: 1 - zoneRedundant: true tags: { 'hidden-title': 'This is visible in the resource name' Environment: 'Non-Prod' diff --git a/avm/res/service-bus/namespace/topic/README.md b/avm/res/service-bus/namespace/topic/README.md index 59c7b43e97..7362055d9e 100644 --- a/avm/res/service-bus/namespace/topic/README.md +++ b/avm/res/service-bus/namespace/topic/README.md @@ -201,6 +201,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Azure Service Bus Data Owner'` + - `'Azure Service Bus Data Receiver'` + - `'Azure Service Bus Data Sender'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-bus/namespace/version.json b/avm/res/service-bus/namespace/version.json index 9a9a06e897..6b6be93891 100644 --- a/avm/res/service-bus/namespace/version.json +++ b/avm/res/service-bus/namespace/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.8", + "version": "0.9", "pathFilters": [ "./main.json" ] diff --git a/avm/res/service-fabric/cluster/README.md b/avm/res/service-fabric/cluster/README.md index bdeeb3417c..de02d4aa07 100644 --- a/avm/res/service-fabric/cluster/README.md +++ b/avm/res/service-fabric/cluster/README.md @@ -79,7 +79,7 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -131,6 +131,44 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-fabric/cluster:' + +// Required parameters +param managementEndpoint = 'https://sfcmin001.westeurope.cloudapp.azure.com:19080' +param name = 'sfcmin001' +param nodeTypes = [ + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Bronze' + ephemeralPorts: { + endPort: 65534 + startPort: 49152 + } + httpGatewayEndpointPort: 19080 + isPrimary: true + name: 'Node01' + } +] +param reliabilityLevel = 'None' +// Non-required parameters +param certificate = { + thumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' +} +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -324,7 +362,7 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -547,6 +585,189 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-fabric/cluster:' + +// Required parameters +param managementEndpoint = 'https://sfcmax001.westeurope.cloudapp.azure.com:19080' +param name = 'sfcmax001' +param nodeTypes = [ + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Silver' + ephemeralPorts: { + endPort: 65534 + startPort: 49152 + } + httpGatewayEndpointPort: 19080 + isPrimary: true + isStateless: false + multipleAvailabilityZones: false + name: 'Node01' + placementProperties: {} + reverseProxyEndpointPort: '' + vmInstanceCount: 5 + } + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Bronze' + ephemeralPorts: { + endPort: 64000 + httpGatewayEndpointPort: 19007 + isPrimary: true + name: 'Node02' + startPort: 49000 + vmInstanceCount: 5 + } + } +] +param reliabilityLevel = 'Silver' +// Non-required parameters +param addOnFeatures = [ + 'BackupRestoreService' + 'DnsService' + 'RepairManager' + 'ResourceMonitorService' +] +param applicationTypes = [ + { + name: 'WordCount' + } +] +param azureActiveDirectory = { + clientApplication: '' + clusterApplication: 'cf33fea8-b30f-424f-ab73-c48d99e0b222' + tenantId: '' +} +param certificateCommonNames = { + commonNames: [ + { + certificateCommonName: 'certcommon' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + } + ] + x509StoreName: 'My' +} +param clientCertificateCommonNames = [ + { + certificateCommonName: 'clientcommoncert1' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + isAdmin: false + } + { + certificateCommonName: 'clientcommoncert2' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC131' + isAdmin: false + } +] +param diagnosticsStorageAccountConfig = { + blobEndpoint: '' + protectedAccountKeyName: 'StorageAccountKey1' + queueEndpoint: '' + storageAccountName: '' + tableEndpoint: '' +} +param fabricSettings = [ + { + name: 'Security' + parameters: [ + { + name: 'ClusterProtectionLevel' + value: 'EncryptAndSign' + } + ] + } + { + name: 'UpgradeService' + parameters: [ + { + name: 'AppPollIntervalInSeconds' + value: '60' + } + ] + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param maxUnusedVersionsToKeep = 2 +param notifications = [ + { + isEnabled: true + notificationCategory: 'WaveProgress' + notificationLevel: 'Critical' + notificationTargets: [ + { + notificationChannel: 'EmailUser' + receivers: [ + 'SomeReceiver' + ] + } + ] + } +] +param roleAssignments = [ + { + name: '26b52f01-eebc-4056-a516-41541369258c' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + clusterName: 'sfcmax001' + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Service Fabric' +} +param upgradeDescription = { + deltaHealthPolicy: { + maxPercentDeltaUnhealthyApplications: 0 + maxPercentDeltaUnhealthyNodes: 0 + maxPercentUpgradeDomainDeltaUnhealthyNodes: 0 + } + forceRestart: false + healthCheckRetryTimeout: '00:45:00' + healthCheckStableDuration: '00:01:00' + healthCheckWaitDuration: '00:00:30' + healthPolicy: { + maxPercentUnhealthyApplications: 0 + maxPercentUnhealthyNodes: 0 + } + upgradeDomainTimeout: '02:00:00' + upgradeReplicaSetCheckTimeout: '1.00:00:00' + upgradeTimeout: '02:00:00' +} +param vmImage = 'Linux' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -712,7 +933,7 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -903,6 +1124,161 @@ module cluster 'br/public:avm/res/service-fabric/cluster:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-fabric/cluster:' + +// Required parameters +param managementEndpoint = 'https://sfcwaf001.westeurope.cloudapp.azure.com:19080' +param name = 'sfcwaf001' +param nodeTypes = [ + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Silver' + ephemeralPorts: { + endPort: 65534 + startPort: 49152 + } + httpGatewayEndpointPort: 19080 + isPrimary: true + isStateless: false + multipleAvailabilityZones: false + name: 'Node01' + placementProperties: {} + reverseProxyEndpointPort: '' + vmInstanceCount: 5 + } + { + applicationPorts: { + endPort: 30000 + startPort: 20000 + } + clientConnectionEndpointPort: 19000 + durabilityLevel: 'Bronze' + ephemeralPorts: { + endPort: 64000 + httpGatewayEndpointPort: 19007 + isPrimary: true + name: 'Node02' + startPort: 49000 + vmInstanceCount: 5 + } + } +] +param reliabilityLevel = 'Silver' +// Non-required parameters +param addOnFeatures = [ + 'BackupRestoreService' + 'DnsService' + 'RepairManager' + 'ResourceMonitorService' +] +param applicationTypes = [ + { + name: 'WordCount' + } +] +param azureActiveDirectory = { + clientApplication: '' + clusterApplication: 'cf33fea8-b30f-424f-ab73-c48d99e0b222' + tenantId: '' +} +param certificate = { + thumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + x509StoreName: 'My' +} +param clientCertificateCommonNames = [ + { + certificateCommonName: 'clientcommoncert1' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC130' + isAdmin: false + } + { + certificateCommonName: 'clientcommoncert2' + certificateIssuerThumbprint: '0AC113D5E1D94C401DDEB0EE2B1B96CC131' + isAdmin: false + } +] +param diagnosticsStorageAccountConfig = { + blobEndpoint: '' + protectedAccountKeyName: 'StorageAccountKey1' + queueEndpoint: '' + storageAccountName: '' + tableEndpoint: '' +} +param fabricSettings = [ + { + name: 'Security' + parameters: [ + { + name: 'ClusterProtectionLevel' + value: 'EncryptAndSign' + } + ] + } + { + name: 'UpgradeService' + parameters: [ + { + name: 'AppPollIntervalInSeconds' + value: '60' + } + ] + } +] +param location = '' +param maxUnusedVersionsToKeep = 2 +param notifications = [ + { + isEnabled: true + notificationCategory: 'WaveProgress' + notificationLevel: 'Critical' + notificationTargets: [ + { + notificationChannel: 'EmailUser' + receivers: [ + 'SomeReceiver' + ] + } + ] + } +] +param tags = { + clusterName: 'sfcwaf001' + 'hidden-title': 'This is visible in the resource name' + resourceType: 'Service Fabric' +} +param upgradeDescription = { + deltaHealthPolicy: { + maxPercentDeltaUnhealthyApplications: 0 + maxPercentDeltaUnhealthyNodes: 0 + maxPercentUpgradeDomainDeltaUnhealthyNodes: 0 + } + forceRestart: false + healthCheckRetryTimeout: '00:45:00' + healthCheckStableDuration: '00:01:00' + healthCheckWaitDuration: '00:00:30' + healthPolicy: { + maxPercentUnhealthyApplications: 0 + maxPercentUnhealthyNodes: 0 + } + upgradeDomainTimeout: '02:00:00' + upgradeReplicaSetCheckTimeout: '1.00:00:00' + upgradeTimeout: '02:00:00' +} +param vmImage = 'Linux' +``` + +
    +

    + ## Parameters **Required parameters** @@ -1339,6 +1715,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/service-networking/traffic-controller/README.md b/avm/res/service-networking/traffic-controller/README.md new file mode 100644 index 0000000000..c85a18a11b --- /dev/null +++ b/avm/res/service-networking/traffic-controller/README.md @@ -0,0 +1,900 @@ +# Application Gateway for Containers `[Microsoft.ServiceNetworking/trafficControllers]` + +This module deploys an Application Gateway for Containers + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Notes](#Notes) +- [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.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.ServiceNetworking/trafficControllers` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers) | +| `Microsoft.ServiceNetworking/trafficControllers/associations` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/associations) | +| `Microsoft.ServiceNetworking/trafficControllers/frontends` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/frontends) | + +## 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/service-networking/traffic-controller:`. + +- [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 trafficController 'br/public:avm/res/service-networking/traffic-controller:' = { + name: 'trafficControllerDeployment' + params: { + // Required parameters + name: 'sntcmin001' + // Non-required parameters + location: '' + } +} +``` + +
    +

    + +

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

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-networking/traffic-controller:' + +// Required parameters +param name = 'sntcmin001' +// Non-required parameters +param location = '' +``` + +
    +

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

    + +via Bicep module + +```bicep +module trafficController 'br/public:avm/res/service-networking/traffic-controller:' = { + name: 'trafficControllerDeployment' + params: { + // Required parameters + name: 'sntcmax001' + // Non-required parameters + associations: [ + { + name: 'association1' + subnetResourceId: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'a6931c52-0b79-4fe9-ad3d-72188dfff379' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + 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 parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sntcmax001" + }, + // Non-required parameters + "associations": { + "value": [ + { + "name": "association1", + "subnetResourceId": "" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "frontends": { + "value": [ + { + "name": "frontend1" + }, + { + "name": "frontend2" + } + ] + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "name": "a6931c52-0b79-4fe9-ad3d-72188dfff379", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "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" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-networking/traffic-controller:' + +// Required parameters +param name = 'sntcmax001' +// Non-required parameters +param associations = [ + { + name: 'association1' + subnetResourceId: '' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param frontends = [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: 'a6931c52-0b79-4fe9-ad3d-72188dfff379' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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 trafficController 'br/public:avm/res/service-networking/traffic-controller:' = { + name: 'trafficControllerDeployment' + params: { + // Required parameters + name: 'sntcwaf001' + // Non-required parameters + associations: [ + { + name: 'association1' + subnetResourceId: '' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + location: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "sntcwaf001" + }, + // Non-required parameters + "associations": { + "value": [ + { + "name": "association1", + "subnetResourceId": "" + } + ] + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "frontends": { + "value": [ + { + "name": "frontend1" + }, + { + "name": "frontend2" + } + ] + }, + "location": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/service-networking/traffic-controller:' + +// Required parameters +param name = 'sntcwaf001' +// Non-required parameters +param associations = [ + { + name: 'association1' + subnetResourceId: '' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param frontends = [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the Application Gateway for Containers to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`associations`](#parameter-associations) | array | List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`frontends`](#parameter-frontends) | array | List of Application Gateway for Containers frontends. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Resource tags. | + +### Parameter: `name` + +Name of the Application Gateway for Containers to create. + +- Required: Yes +- Type: string + +### Parameter: `associations` + +List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-associationsname) | string | The name of the Application Gateway for Containers association. | +| [`subnetResourceId`](#parameter-associationssubnetresourceid) | string | The resource ID of the subnet to associate with the Application Gateway for Containers. | + +### Parameter: `associations.name` + +The name of the Application Gateway for Containers association. + +- Required: Yes +- Type: string + +### Parameter: `associations.subnetResourceId` + +The resource ID of the subnet to associate with the Application Gateway for Containers. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingslogcategoriesandgroupscategory) | string | Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. | +| [`categoryGroup`](#parameter-diagnosticsettingslogcategoriesandgroupscategorygroup) | string | Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. | +| [`enabled`](#parameter-diagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.category` + +Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.categoryGroup` + +Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`category`](#parameter-diagnosticsettingsmetriccategoriescategory) | string | Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-diagnosticsettingsmetriccategoriesenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `diagnosticSettings.metricCategories.category` + +Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics. + +- Required: Yes +- Type: string + +### Parameter: `diagnosticSettings.metricCategories.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `frontends` + +List of Application Gateway for Containers frontends. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-frontendsname) | string | The name of the Application Gateway for Containers frontend. | + +### Parameter: `frontends.name` + +The name of the Application Gateway for Containers frontend. + +- Required: Yes +- Type: string + +### 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: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**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. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`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.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- 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` + +Resource tags. + +- Required: No +- Type: object + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `associations` | array | The associations of the Application Gateway for Containers. | +| `configurationEndpoints` | array | The configuration endpoints of the Application Gateway for Containers. | +| `frontends` | array | The frontends of the Application Gateway for Containers. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Application Gateway for Containers. | +| `resourceGroupName` | string | The name of the resource group the resource was created in. | +| `resourceId` | string | The resource ID of the Application Gateway for Containers. | + +## Notes + +> **Limitation**: At this time, the number of associations is limited to 1 (Source: [Application Gateway for Containers associations](https://learn.microsoft.com/en-us/azure/application-gateway/for-containers/application-gateway-for-containers-components#application-gateway-for-containers-associations)) + +## 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/service-networking/traffic-controller/association/README.md b/avm/res/service-networking/traffic-controller/association/README.md new file mode 100644 index 0000000000..87488abfe2 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/association/README.md @@ -0,0 +1,79 @@ +# Application Gateway for Containers Association `[Microsoft.ServiceNetworking/trafficControllers/associations]` + +This module deploys an Application Gateway for Containers Association + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.ServiceNetworking/trafficControllers/associations` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/associations) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the association to create. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`trafficControllerName`](#parameter-trafficcontrollername) | string | The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all Resources. | + +**Reuired parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-subnetresourceid) | string | The resource ID of the subnet to associate with the traffic controller. | + +### Parameter: `name` + +Name of the association to create. + +- Required: Yes +- Type: string + +### Parameter: `trafficControllerName` + +The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `subnetResourceId` + +The resource ID of the subnet to associate with the traffic controller. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the association. | +| `resourceGroupName` | string | The name of the resource group the resource was created in. | +| `resourceId` | string | The resource ID of the association. | +| `subnetResourceId` | string | The resource ID of the associated subnet. | diff --git a/avm/res/service-networking/traffic-controller/association/main.bicep b/avm/res/service-networking/traffic-controller/association/main.bicep new file mode 100644 index 0000000000..70cc047a29 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/association/main.bicep @@ -0,0 +1,51 @@ +metadata name = 'Application Gateway for Containers Association' +metadata description = 'This module deploys an Application Gateway for Containers Association' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the association to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment.') +param trafficControllerName string + +@description('Reuired. The resource ID of the subnet to associate with the traffic controller.') +param subnetResourceId string + +// ============== // +// Resources // +// ============== // + +resource trafficController 'Microsoft.ServiceNetworking/trafficControllers@2023-11-01' existing = { + name: trafficControllerName +} + +resource association 'Microsoft.ServiceNetworking/trafficControllers/associations@2023-11-01' = { + name: name + parent: trafficController + location: location + properties: { + associationType: 'subnets' + subnet: { + id: subnetResourceId + } + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the association.') +output resourceId string = association.id + +@description('The name of the association.') +output name string = association.name + +@description('The name of the resource group the resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the associated subnet.') +output subnetResourceId string = association.properties.subnet.id diff --git a/avm/res/service-networking/traffic-controller/association/main.json b/avm/res/service-networking/traffic-controller/association/main.json new file mode 100644 index 0000000000..638bc670f4 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/association/main.json @@ -0,0 +1,85 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "17751059838446450774" + }, + "name": "Application Gateway for Containers Association", + "description": "This module deploys an Application Gateway for Containers Association", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the association to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Reuired. The resource ID of the subnet to associate with the traffic controller." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/associations", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "associationType": "subnets", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the association." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the association." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the associated subnet." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name')), '2023-11-01').subnet.id]" + } + } +} \ No newline at end of file diff --git a/avm/res/service-networking/traffic-controller/frontend/README.md b/avm/res/service-networking/traffic-controller/frontend/README.md new file mode 100644 index 0000000000..c9447a6ba3 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/frontend/README.md @@ -0,0 +1,66 @@ +# Application Gateway for Containers Frontend `[Microsoft.ServiceNetworking/trafficControllers/frontends]` + +This module deploys an Application Gateway for Containers Frontend + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.ServiceNetworking/trafficControllers/frontends` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ServiceNetworking/2023-11-01/trafficControllers/frontends) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the frontend to create. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`trafficControllerName`](#parameter-trafficcontrollername) | string | The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`location`](#parameter-location) | string | Location for all Resources. | + +### Parameter: `name` + +Name of the frontend to create. + +- Required: Yes +- Type: string + +### Parameter: `trafficControllerName` + +The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `fqdn` | string | The FQDN of the frontend. | +| `name` | string | The name of the frontend. | +| `resourceGroupName` | string | The name of the resource group the resource was created in. | +| `resourceId` | string | The resource ID of the frontend. | diff --git a/avm/res/service-networking/traffic-controller/frontend/main.bicep b/avm/res/service-networking/traffic-controller/frontend/main.bicep new file mode 100644 index 0000000000..973eb532a7 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/frontend/main.bicep @@ -0,0 +1,43 @@ +metadata name = 'Application Gateway for Containers Frontend' +metadata description = 'This module deploys an Application Gateway for Containers Frontend' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the frontend to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment.') +param trafficControllerName string + +// ============== // +// Resources // +// ============== // + +resource trafficController 'Microsoft.ServiceNetworking/trafficControllers@2023-11-01' existing = { + name: trafficControllerName +} + +resource frontend 'Microsoft.ServiceNetworking/trafficControllers/frontends@2023-11-01' = { + name: name + parent: trafficController + location: location + properties: {} +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the frontend.') +output resourceId string = frontend.id + +@description('The name of the frontend.') +output name string = frontend.name + +@description('The name of the resource group the resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The FQDN of the frontend.') +output fqdn string = frontend.properties.fqdn diff --git a/avm/res/service-networking/traffic-controller/frontend/main.json b/avm/res/service-networking/traffic-controller/frontend/main.json new file mode 100644 index 0000000000..f3fb57ad7e --- /dev/null +++ b/avm/res/service-networking/traffic-controller/frontend/main.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "12093954076612099884" + }, + "name": "Application Gateway for Containers Frontend", + "description": "This module deploys an Application Gateway for Containers Frontend", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the frontend to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/frontends", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the frontend." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the frontend." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the frontend." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name')), '2023-11-01').fqdn]" + } + } +} \ No newline at end of file diff --git a/avm/res/service-networking/traffic-controller/main.bicep b/avm/res/service-networking/traffic-controller/main.bicep new file mode 100644 index 0000000000..2ac083b224 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/main.bicep @@ -0,0 +1,301 @@ +metadata name = 'Application Gateway for Containers' +metadata description = 'This module deploys an Application Gateway for Containers' +metadata owner = 'Azure/module-maintainers' + +@description('Required. Name of the Application Gateway for Containers to create.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Resource tags.') +param tags object? + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. List of Application Gateway for Containers frontends.') +param frontends frontendType + +@description('Optional. List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1.') +param associations associationType + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.servicenetworking-trafficcontroller.${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 trafficController 'Microsoft.ServiceNetworking/trafficControllers@2023-11-01' = { + name: name + location: location + tags: tags + properties: {} +} + +resource trafficController_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: trafficController +} + +resource trafficController_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: trafficController + } +] + +resource trafficController_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid( + trafficController.id, + roleAssignment.principalId, + roleAssignment.roleDefinitionId + ) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + 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: trafficController + } +] + +module trafficController_frontends 'frontend/main.bicep' = [ + for (frontend, index) in (frontends ?? []): { + name: '${uniqueString(deployment().name, location)}-TrafficController-Frontend-${index}' + params: { + trafficControllerName: trafficController.name + name: frontend.name + location: location + } + } +] + +module trafficController_associations 'association/main.bicep' = [ + for (association, index) in (associations ?? []): { + name: '${uniqueString(deployment().name, location)}-TrafficController-Association-${index}' + params: { + trafficControllerName: trafficController.name + name: association.name + location: location + subnetResourceId: association.subnetResourceId + } + } +] + +// ============ // +// Outputs // +// ============ // + +@description('The resource ID of the Application Gateway for Containers.') +output resourceId string = trafficController.id + +@description('The name of the Application Gateway for Containers.') +output name string = trafficController.name + +@description('The name of the resource group the resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = trafficController.location + +@description('The configuration endpoints of the Application Gateway for Containers.') +output configurationEndpoints string[] = trafficController.properties.configurationEndpoints + +@description('The frontends of the Application Gateway for Containers.') +output frontends array = [ + for (frontend, i) in (!empty(frontends) ? array(frontends) : []): { + name: trafficController_frontends[i].outputs.name + resourceId: trafficController_frontends[i].outputs.resourceId + fqdn: trafficController_frontends[i].outputs.fqdn + } +] + +@description('The associations of the Application Gateway for Containers.') +output associations array = [ + for (association, i) in (!empty(associations) ? array(associations) : []): { + name: trafficController_associations[i].outputs.name + resourceId: trafficController_associations[i].outputs.resourceId + subnetResourceId: trafficController_associations[i].outputs.subnetResourceId + } +] + +// ================ // +// Definitions // +// ================ // + +type frontendType = { + @description('Required. The name of the Application Gateway for Containers frontend.') + name: string +}[]? + +@maxLength(1) +type associationType = { + @description('Required. The name of the Application Gateway for Containers association.') + name: string + + @description('Required. The resource ID of the subnet to associate with the Application Gateway for Containers.') + subnetResourceId: string +}[]? + +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('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') + name: string? + + @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? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to `[]` to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to `[]` to disable metric collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + + @description('Optional. Enable or disable the category explicitly. Default is `true`.') + enabled: bool? + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/res/service-networking/traffic-controller/main.json b/avm/res/service-networking/traffic-controller/main.json new file mode 100644 index 0000000000..aa85cfc38c --- /dev/null +++ b/avm/res/service-networking/traffic-controller/main.json @@ -0,0 +1,742 @@ +{ + "$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.30.23.60470", + "templateHash": "13555357375349247834" + }, + "name": "Application Gateway for Containers", + "description": "This module deploys an Application Gateway for Containers", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "frontendType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Application Gateway for Containers frontend." + } + } + } + }, + "nullable": true + }, + "associationType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Application Gateway for Containers association." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the subnet to associate with the Application Gateway for Containers." + } + } + } + }, + "nullable": true, + "maxLength": 1 + }, + "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": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Gateway for Containers to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "frontends": { + "$ref": "#/definitions/frontendType", + "metadata": { + "description": "Optional. List of Application Gateway for Containers frontends." + } + }, + "associations": { + "$ref": "#/definitions/associationType", + "metadata": { + "description": "Optional. List of Application Gateway for Containers associations. At this time, the number of associations is limited to 1." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[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": "2024-03-01", + "name": "[format('46d3xbcp.res.servicenetworking-trafficcontroller.{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" + } + } + } + } + }, + "trafficController": { + "type": "Microsoft.ServiceNetworking/trafficControllers", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "trafficController_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.ServiceNetworking/trafficControllers/{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": [ + "trafficController" + ] + }, + "trafficController_diagnosticSettings": { + "copy": { + "name": "trafficController_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ServiceNetworking/trafficControllers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "trafficController" + ] + }, + "trafficController_roleAssignments": { + "copy": { + "name": "trafficController_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ServiceNetworking/trafficControllers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ServiceNetworking/trafficControllers', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "trafficController" + ] + }, + "trafficController_frontends": { + "copy": { + "name": "trafficController_frontends", + "count": "[length(coalesce(parameters('frontends'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-TrafficController-Frontend-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "trafficControllerName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('frontends'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "12093954076612099884" + }, + "name": "Application Gateway for Containers Frontend", + "description": "This module deploys an Application Gateway for Containers Frontend", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the frontend to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/frontends", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": {} + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the frontend." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the frontend." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The FQDN of the frontend." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/frontends', parameters('trafficControllerName'), parameters('name')), '2023-11-01').fqdn]" + } + } + } + }, + "dependsOn": [ + "trafficController" + ] + }, + "trafficController_associations": { + "copy": { + "name": "trafficController_associations", + "count": "[length(coalesce(parameters('associations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-TrafficController-Association-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "trafficControllerName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('associations'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('associations'), createArray())[copyIndex()].subnetResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "17751059838446450774" + }, + "name": "Application Gateway for Containers Association", + "description": "This module deploys an Application Gateway for Containers Association", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the association to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "trafficControllerName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Gateway for Containers instance. Required if the template is used in a standalone deployment." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Reuired. The resource ID of the subnet to associate with the traffic controller." + } + } + }, + "resources": [ + { + "type": "Microsoft.ServiceNetworking/trafficControllers/associations", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('trafficControllerName'), parameters('name'))]", + "location": "[parameters('location')]", + "properties": { + "associationType": "subnets", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the association." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the association." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the associated subnet." + }, + "value": "[reference(resourceId('Microsoft.ServiceNetworking/trafficControllers/associations', parameters('trafficControllerName'), parameters('name')), '2023-11-01').subnet.id]" + } + } + } + }, + "dependsOn": [ + "trafficController" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Application Gateway for Containers." + }, + "value": "[resourceId('Microsoft.ServiceNetworking/trafficControllers', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Application Gateway for Containers." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('trafficController', '2023-11-01', 'full').location]" + }, + "configurationEndpoints": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The configuration endpoints of the Application Gateway for Containers." + }, + "value": "[reference('trafficController').configurationEndpoints]" + }, + "frontends": { + "type": "array", + "metadata": { + "description": "The frontends of the Application Gateway for Containers." + }, + "copy": { + "count": "[length(if(not(empty(parameters('frontends'))), array(parameters('frontends')), createArray()))]", + "input": { + "name": "[reference(format('trafficController_frontends[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('trafficController_frontends[{0}]', copyIndex())).outputs.resourceId.value]", + "fqdn": "[reference(format('trafficController_frontends[{0}]', copyIndex())).outputs.fqdn.value]" + } + } + }, + "associations": { + "type": "array", + "metadata": { + "description": "The associations of the Application Gateway for Containers." + }, + "copy": { + "count": "[length(if(not(empty(parameters('associations'))), array(parameters('associations')), createArray()))]", + "input": { + "name": "[reference(format('trafficController_associations[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('trafficController_associations[{0}]', copyIndex())).outputs.resourceId.value]", + "subnetResourceId": "[reference(format('trafficController_associations[{0}]', copyIndex())).outputs.subnetResourceId.value]" + } + } + } + } +} \ No newline at end of file diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/defaults/main.test.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..3204196c73 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-servicenetworking-trafficcontrollers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sntcmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + } + } +] diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/max/dependencies.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..ee481bbc78 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/max/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + delegations: [ + { + name: 'Microsoft.ServiceNetworking.trafficControllers' + properties: { + serviceName: 'Microsoft.ServiceNetworking/trafficControllers' + } + } + ] + } + } + ] + } +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created default Virtual Network Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..3636eeb929 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/max/main.test.bicep @@ -0,0 +1,131 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-servicenetworking-trafficcontrollers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sntcmax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + associations: [ + { + name: 'association1' + subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + name: 'a6931c52-0b79-4fe9-ad3d-72188dfff379' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + 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' + } + ] + diagnosticSettings: [ + { + name: 'customSetting' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + } +] diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..c71e8b7ac8 --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,38 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 24, 0) + delegations: [ + { + name: 'Microsoft.ServiceNetworking.trafficControllers' + properties: { + serviceName: 'Microsoft.ServiceNetworking/trafficControllers' + } + } + ] + } + } + ] + } +} + +@description('The resource ID of the created default Virtual Network Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id diff --git a/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/main.test.bicep b/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..499b6a760a --- /dev/null +++ b/avm/res/service-networking/traffic-controller/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,98 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-servicenetworking-trafficcontrollers-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'sntcwaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + frontends: [ + { + name: 'frontend1' + } + { + name: 'frontend2' + } + ] + associations: [ + { + name: 'association1' + subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + diagnosticSettings: [ + { + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + } +] diff --git a/avm/res/service-networking/traffic-controller/version.json b/avm/res/service-networking/traffic-controller/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/service-networking/traffic-controller/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/signal-r-service/signal-r/README.md b/avm/res/signal-r-service/signal-r/README.md index 35f25de4aa..3612033f31 100644 --- a/avm/res/signal-r-service/signal-r/README.md +++ b/avm/res/signal-r-service/signal-r/README.md @@ -64,7 +64,7 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/signal-r:' + +// Required parameters +param name = 'srsdrmin-001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -196,7 +212,7 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -326,6 +342,106 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/signal-r:' + +// Required parameters +param name = 'srssrmax-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param kind = 'SignalR' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srssrmax-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param roleAssignments = [ + { + name: 'd8c98876-5377-4b49-98ae-41a8b5537761' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Standard_S1' +param tags = { + 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. @@ -403,7 +519,7 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -496,6 +612,73 @@ module signalR 'br/public:avm/res/signal-r-service/signal-r:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/signal-r:' + +// Required parameters +param name = 'srssrwaf-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param kind = 'SignalR' +param location = '' +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srssrwaf-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param sku = 'Standard_S1' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -983,6 +1166,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1129,6 +1323,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'SignalR AccessKey Reader'` + - `'SignalR App Server'` + - `'SignalR REST API Owner'` + - `'SignalR REST API Reader'` + - `'SignalR Service Owner'` + - `'SignalR/Web PubSub Contributor'` + - `'User Access Administrator'` + - `'Web PubSub Service Owner (Preview)'` + - `'Web PubSub Service Reader (Preview)'` **Required parameters** 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 46fb8b2483..c060863897 100644 --- a/avm/res/signal-r-service/web-pub-sub/README.md +++ b/avm/res/signal-r-service/web-pub-sub/README.md @@ -64,7 +64,7 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/web-pub-sub:' + +// Required parameters +param name = 'srswpsmin-001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -199,7 +215,7 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -332,6 +348,109 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/web-pub-sub:' + +// Required parameters +param name = 'srswpsmax-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true +} +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srswpsmax-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'webpubsub' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param roleAssignments = [ + { + name: '8e40bf2f-0457-4292-a83a-eedc36d04f6a' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Standard_S1' +param tags = { + 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. @@ -412,7 +531,7 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -508,6 +627,76 @@ module webPubSub 'br/public:avm/res/signal-r-service/web-pub-sub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/signal-r-service/web-pub-sub:' + +// Required parameters +param name = 'srswpswaf-001' +// Non-required parameters +param capacity = 2 +param clientCertEnabled = false +param disableAadAuth = false +param disableLocalAuth = true +param location = '' +param managedIdentities = { + systemAssigned: true +} +param networkAcls = { + defaultAction: 'Allow' + privateEndpoints: [ + { + allow: [] + deny: [ + 'ServerConnection' + 'Trace' + ] + name: 'pe-srswpswaf-001' + } + ] + publicNetwork: { + allow: [] + deny: [ + 'RESTAPI' + 'Trace' + ] + } +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'webpubsub' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param resourceLogConfigurationsToEnable = [ + 'ConnectivityLogs' +] +param sku = 'Standard_S1' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -952,6 +1141,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1098,6 +1298,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'SignalR AccessKey Reader'` + - `'SignalR App Server'` + - `'SignalR REST API Owner'` + - `'SignalR REST API Reader'` + - `'SignalR Service Owner'` + - `'SignalR/Web PubSub Contributor'` + - `'User Access Administrator'` + - `'Web PubSub Service Owner (Preview)'` + - `'Web PubSub Service Reader (Preview)'` **Required parameters** diff --git a/avm/res/sql/instance-pool/README.md b/avm/res/sql/instance-pool/README.md index 544047ed12..2437ec09f2 100644 --- a/avm/res/sql/instance-pool/README.md +++ b/avm/res/sql/instance-pool/README.md @@ -54,7 +54,7 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -79,6 +79,23 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/instance-pool:' + +// Required parameters +param name = '' +param subnetResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Well-Architected Framework. @@ -107,7 +124,7 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -135,6 +152,24 @@ module instancePool 'br/public:avm/res/sql/instance-pool:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/instance-pool:' + +// Required parameters +param name = '' +param subnetResourceId = '' +// Non-required parameters +param location = '' +param skuName = 'GP_Gen8IM' +``` + +
    +

    + ## Parameters **Required parameters** diff --git a/avm/res/sql/managed-instance/README.md b/avm/res/sql/managed-instance/README.md index a9394f7cf0..a255e2ff20 100644 --- a/avm/res/sql/managed-instance/README.md +++ b/avm/res/sql/managed-instance/README.md @@ -69,7 +69,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -100,6 +100,25 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmimin' +param subnetResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -234,7 +253,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -412,6 +431,130 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmimax' +param subnetResourceId = '' +// Non-required parameters +param collation = 'SQL_Latin1_General_CP1_CI_AS' +param databases = [ + { + backupLongTermRetentionPolicies: { + name: 'default' + } + backupShortTermRetentionPolicies: { + name: 'default' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'sqlmimax-db-001' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsZonePartner = '' +param encryptionProtectorObj = { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' +} +param hardwareFamily = 'Gen5' +param keys = [ + { + name: '' + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param licenseType = 'LicenseIncluded' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param proxyOverride = 'Proxy' +param publicDataEndpointEnabled = false +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securityAlertPoliciesObj = { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' +} +param servicePrincipal = 'SystemAssigned' +param skuName = 'GP_Gen5' +param skuTier = 'GeneralPurpose' +param storageSizeInGB = 32 +param timezoneId = 'UTC' +param vCores = 4 +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +``` + +
    +

    + ### Example 3: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -466,7 +609,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -528,6 +671,50 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmivln' +param subnetResourceId = '' +// Non-required parameters +param location = '' +param managedIdentities = { + systemAssigned: true +} +param securityAlertPoliciesObj = { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' +} +param vulnerabilityAssessmentsObj = { + createStorageRoleAssignment: true + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + useStorageAccountAccessKey: false +} +``` + +
    +

    + ### Example 4: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -645,7 +832,7 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -804,6 +991,113 @@ module managedInstance 'br/public:avm/res/sql/managed-instance:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/managed-instance:' + +// Required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param name = 'sqlmiwaf' +param subnetResourceId = '' +// Non-required parameters +param collation = 'SQL_Latin1_General_CP1_CI_AS' +param databases = [ + { + backupLongTermRetentionPolicies: { + name: 'default' + } + backupShortTermRetentionPolicies: { + name: 'default' + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + name: 'sqlmiwaf-db-001' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param dnsZonePartner = '' +param encryptionProtectorObj = { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' +} +param hardwareFamily = 'Gen5' +param keys = [ + { + name: '' + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param licenseType = 'LicenseIncluded' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param proxyOverride = 'Proxy' +param publicDataEndpointEnabled = false +param securityAlertPoliciesObj = { + emailAccountAdmins: true + name: 'default' + state: 'Enabled' +} +param servicePrincipal = 'SystemAssigned' +param skuName = 'GP_Gen5' +param skuTier = 'GeneralPurpose' +param storageSizeInGB = 32 +param timezoneId = 'UTC' +param vCores = 4 +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1286,6 +1580,19 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reservation Purchaser'` + - `'Role Based Access Control Administrator (Preview)'` + - `'SQL DB Contributor'` + - `'SQL Managed Instance Contributor'` + - `'SQL Security Manager'` + - `'SQL Server Contributor'` + - `'SqlDb Migration Role'` + - `'SqlMI Migration Role'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index e4306982f2..e38347c937 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -82,7 +82,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -112,6 +112,28 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsadmin' +// Non-required parameters +param administrators = { + azureADOnlyAuthentication: true + login: 'myspn' + principalType: 'Application' + sid: '' +} +param location = '' +``` + +
    +

    + ### Example 2: _With audit settings_ This instance deploys the module with auditing settings. @@ -148,7 +170,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -188,6 +210,32 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'ssaud001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param auditSettings = { + isManagedIdentityInUse: true + state: 'Enabled' + storageAccountResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +``` + +
    +

    + ### Example 3: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -216,7 +264,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -244,6 +292,24 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'ssmin001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param location = '' +``` + +
    +

    + ### Example 4: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -270,7 +336,6 @@ module server 'br/public:avm/res/sql/server:' = { backupShortTermRetentionPolicy: { retentionDays: 14 } - capacity: 0 collation: 'SQL_Latin1_General_CP1_CI_AS' diagnosticSettings: [ { @@ -289,6 +354,7 @@ module server 'br/public:avm/res/sql/server:' = { licenseType: 'LicenseIncluded' maxSizeBytes: 34359738368 name: 'sqlsmaxdb-001' + skuCapacity: 0 skuName: 'ElasticPool' skuTier: 'GeneralPurpose' } @@ -413,7 +479,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -438,7 +504,6 @@ module server 'br/public:avm/res/sql/server:' = { "backupShortTermRetentionPolicy": { "retentionDays": 14 }, - "capacity": 0, "collation": "SQL_Latin1_General_CP1_CI_AS", "diagnosticSettings": [ { @@ -457,6 +522,7 @@ module server 'br/public:avm/res/sql/server:' = { "licenseType": "LicenseIncluded", "maxSizeBytes": 34359738368, "name": "sqlsmaxdb-001", + "skuCapacity": 0, "skuName": "ElasticPool", "skuTier": "GeneralPurpose" } @@ -608,6 +674,165 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsmax' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + backupLongTermRetentionPolicy: { + monthlyRetention: 'P6M' + } + backupShortTermRetentionPolicy: { + retentionDays: 14 + } + collation: 'SQL_Latin1_General_CP1_CI_AS' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + elasticPoolId: '' + encryptionProtectorObj: { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' + } + licenseType: 'LicenseIncluded' + maxSizeBytes: 34359738368 + name: 'sqlsmaxdb-001' + skuCapacity: 0 + skuName: 'ElasticPool' + skuTier: 'GeneralPurpose' + } +] +param elasticPools = [ + { + maintenanceConfigurationId: '' + name: 'sqlsmax-ep-001' + skuCapacity: 10 + skuName: 'GP_Gen5' + skuTier: 'GeneralPurpose' + } +] +param firewallRules = [ + { + endIpAddress: '0.0.0.0' + name: 'AllowAllWindowsAzureIps' + startIpAddress: '0.0.0.0' + } +] +param keys = [ + { + name: '' + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param restrictOutboundNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '7027a5c5-d1b1-49e0-80cc-ffdff3a3ada9' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param securityAlertPolicies = [ + { + emailAccountAdmins: true + name: 'Default' + state: 'Enabled' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkRules = [ + { + ignoreMissingVnetServiceEndpoint: true + name: 'newVnetRule1' + virtualNetworkSubnetId: '' + } +] +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' +} +``` + +
    +

    + ### Example 5: _With a secondary database_ This instance deploys the module with a secondary database. @@ -651,7 +876,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -698,6 +923,39 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsec-sec' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + createMode: 'Secondary' + maxSizeBytes: 2147483648 + name: '' + skuName: 'Basic' + skuTier: 'Basic' + sourceDatabaseResourceId: '' + } +] +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 6: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -757,7 +1015,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -826,6 +1084,55 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlsvln' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param securityAlertPolicies = [ + { + emailAccountAdmins: true + name: 'Default' + state: 'Enabled' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param vulnerabilityAssessmentsObj = { + createStorageRoleAssignment: true + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' + useStorageAccountAccessKey: false +} +``` + +
    +

    + ### Example 7: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -857,7 +1164,6 @@ module server 'br/public:avm/res/sql/server:' = { backupShortTermRetentionPolicy: { retentionDays: 14 } - capacity: 0 collation: 'SQL_Latin1_General_CP1_CI_AS' diagnosticSettings: [ { @@ -876,6 +1182,7 @@ module server 'br/public:avm/res/sql/server:' = { licenseType: 'LicenseIncluded' maxSizeBytes: 34359738368 name: 'sqlswafdb-001' + skuCapacity: 0 skuName: 'ElasticPool' skuTier: 'GeneralPurpose' } @@ -960,7 +1267,7 @@ module server 'br/public:avm/res/sql/server:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -988,7 +1295,6 @@ module server 'br/public:avm/res/sql/server:' = { "backupShortTermRetentionPolicy": { "retentionDays": 14 }, - "capacity": 0, "collation": "SQL_Latin1_General_CP1_CI_AS", "diagnosticSettings": [ { @@ -1007,6 +1313,7 @@ module server 'br/public:avm/res/sql/server:' = { "licenseType": "LicenseIncluded", "maxSizeBytes": 34359738368, "name": "sqlswafdb-001", + "skuCapacity": 0, "skuName": "ElasticPool", "skuTier": "GeneralPurpose" } @@ -1112,6 +1419,130 @@ module server 'br/public:avm/res/sql/server:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'sqlswaf' +// Non-required parameters +param administrators = { + azureADOnlyAuthentication: true + login: 'myspn' + principalType: 'Application' + sid: '' + tenantId: '' +} +param databases = [ + { + backupLongTermRetentionPolicy: { + monthlyRetention: 'P6M' + } + backupShortTermRetentionPolicy: { + retentionDays: 14 + } + collation: 'SQL_Latin1_General_CP1_CI_AS' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + elasticPoolId: '' + encryptionProtectorObj: { + serverKeyName: '' + serverKeyType: 'AzureKeyVault' + } + licenseType: 'LicenseIncluded' + maxSizeBytes: 34359738368 + name: 'sqlswafdb-001' + skuCapacity: 0 + skuName: 'ElasticPool' + skuTier: 'GeneralPurpose' + } +] +param elasticPools = [ + { + maintenanceConfigurationId: '' + name: 'sqlswaf-ep-001' + skuCapacity: 10 + skuName: 'GP_Gen5' + skuTier: 'GeneralPurpose' + } +] +param keys = [ + { + serverKeyType: 'AzureKeyVault' + uri: '' + } +] +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param primaryUserAssignedIdentityId = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'sqlServer' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param restrictOutboundNetworkAccess = 'Disabled' +param securityAlertPolicies = [ + { + emailAccountAdmins: true + name: 'Default' + state: 'Enabled' + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param virtualNetworkRules = [ + { + ignoreMissingVnetServiceEndpoint: true + name: 'newVnetRule1' + virtualNetworkSubnetId: '' + } +] +param vulnerabilityAssessmentsObj = { + emailSubscriptionAdmins: true + name: 'default' + recurringScansEmails: [ + 'test1@contoso.com' + 'test2@contoso.com' + ] + recurringScansIsEnabled: true + storageAccountResourceId: '' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1722,6 +2153,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1865,6 +2307,19 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reservation Purchaser'` + - `'Role Based Access Control Administrator'` + - `'SQL DB Contributor'` + - `'SQL Managed Instance Contributor'` + - `'SQL Security Manager'` + - `'SQL Server Contributor'` + - `'SqlDb Migration Role'` + - `'SqlMI Migration Role'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/sql/server/tests/e2e/max/main.test.bicep b/avm/res/sql/server/tests/e2e/max/main.test.bicep index 662e8900fd..ec70abad1a 100644 --- a/avm/res/sql/server/tests/e2e/max/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/max/main.test.bicep @@ -125,7 +125,7 @@ module testDeployment '../../../main.bicep' = { collation: 'SQL_Latin1_General_CP1_CI_AS' skuTier: 'GeneralPurpose' skuName: 'ElasticPool' - capacity: 0 + skuCapacity: 0 maxSizeBytes: 34359738368 licenseType: 'LicenseIncluded' diagnosticSettings: [ diff --git a/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep b/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep index f444f7bf12..2f7e279f3b 100644 --- a/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/sql/server/tests/e2e/waf-aligned/main.test.bicep @@ -100,7 +100,7 @@ module testDeployment '../../../main.bicep' = { collation: 'SQL_Latin1_General_CP1_CI_AS' skuTier: 'GeneralPurpose' skuName: 'ElasticPool' - capacity: 0 + skuCapacity: 0 maxSizeBytes: 34359738368 licenseType: 'LicenseIncluded' diagnosticSettings: [ diff --git a/avm/res/storage/storage-account/README.md b/avm/res/storage/storage-account/README.md index 557a0ff537..b5105ee977 100644 --- a/avm/res/storage/storage-account/README.md +++ b/avm/res/storage/storage-account/README.md @@ -22,18 +22,18 @@ This module deploys a Storage Account. | `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | -| `Microsoft.Storage/storageAccounts` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts) | +| `Microsoft.Storage/storageAccounts` | [2023-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-05-01/storageAccounts) | | `Microsoft.Storage/storageAccounts/blobServices` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices) | | `Microsoft.Storage/storageAccounts/blobServices/containers` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers) | | `Microsoft.Storage/storageAccounts/blobServices/containers/immutabilityPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2022-09-01/storageAccounts/blobServices/containers/immutabilityPolicies) | -| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | | `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | -| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | | `Microsoft.Storage/storageAccounts/managementPolicies` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/managementPolicies) | -| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | ## Usage examples @@ -83,7 +83,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -111,6 +111,24 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssablob001' +// Non-required parameters +param kind = 'BlobStorage' +param location = '' +param skuName = 'Standard_LRS' +``` + +
    +

    + ### Example 2: _Deploying as a Block Blob Storage_ This instance deploys the module as a Premium Block Blob Storage account. @@ -139,7 +157,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -167,6 +185,24 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssablock001' +// Non-required parameters +param kind = 'BlockBlobStorage' +param location = '' +param skuName = 'Premium_LRS' +``` + +
    +

    + ### Example 3: _Using only changefeed configuration_ This instance deploys the module with the minimum set of required parameters for the changefeed configuration. @@ -197,7 +233,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -227,6 +263,26 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssachf001' +// Non-required parameters +param allowBlobPublicAccess = false +param blobServices = { + changeFeedEnabled: true +} +param location = '' +``` + +
    +

    + ### Example 4: _Using only defaults_ This instance deploys the module with the minimum set of required parameters. @@ -258,7 +314,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -289,6 +345,27 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssamin001' +// Non-required parameters +param allowBlobPublicAccess = false +param location = '' +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' +} +``` + +
    +

    + ### Example 5: _Deploying with a key vault reference to save secrets_ This instance deploys the module saving all its secrets in a key vault. @@ -322,7 +399,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -353,6 +430,29 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'kvref' +// Non-required parameters +param location = '' +param secretsExportConfiguration = { + accessKey1: 'custom-key1-name' + accessKey2: 'custom-key2-name' + connectionString1: 'custom-connectionString1-name' + connectionString2: 'custom-connectionString2-name' + keyVaultResourceId: '' +} +``` + +
    +

    + ### Example 6: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -799,7 +899,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1283,6 +1383,442 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssamax001' +// Non-required parameters +param allowBlobPublicAccess = false +param blobServices = { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + name: 'avdscripts' + publicAccess: 'None' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + allowProtectedAppendWrites: false + enableWORM: true + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + WORMRetention: 666 + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + lastAccessTimeTrackingPolicyEnabled: true +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableHierarchicalNamespace = true +enableNfsV3: true +param enableSftp = true +param fileServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + shares: [ + { + accessTier: 'Hot' + name: 'avdprofiles' + roleAssignments: [ + { + name: 'cff1213b-7877-4425-b67c-bb1de8950dfb' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] +} +param largeFileSharesState = 'Enabled' +param localUsers = [ + { + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + name: 'testuser' + permissionScopes: [ + { + permissions: 'r' + resourceName: 'avdscripts' + service: 'blob' + } + ] + storageAccountName: 'ssamax001' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param managementPolicyRules = [ + { + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + } +] +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + resourceAccessRules: [ + { + resourceId: '' + tenantId: '' + } + ] + virtualNetworkRules: [ + { + action: 'Allow' + id: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'table' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'queue' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'file' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'web' + subnetResourceId: '' + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'dfs' + subnetResourceId: '' + } +] +param queueServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + queues: [ + { + metadata: { + key1: 'value1' + key2: 'value2' + } + name: 'queue1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + metadata: {} + name: 'queue2' + } + ] +} +param requireInfrastructureEncryption = true +param roleAssignments = [ + { + name: '30b99723-a3d8-4e31-8872-b80c960d62bd' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sasExpirationPeriod = '180.00:00:00' +param skuName = 'Standard_LRS' +param tableServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + tables: [ + { + name: 'table1' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + { + name: 'table2' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + } + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ### Example 7: _Deploying with a NFS File Share_ This instance deploys the module with a NFS File Share. @@ -1319,7 +1855,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1357,6 +1893,32 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssanfs001' +// Non-required parameters +param fileServices = { + shares: [ + { + enabledProtocols: 'NFS' + name: 'nfsfileshare' + } + ] +} +param kind = 'FileStorage' +param location = '' +param skuName = 'Premium_LRS' +``` + +
    +

    + ### Example 8: _Using Customer-Managed-Keys with System-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity. This required the service to be deployed twice, once as a pre-requisite to create the System-Assigned Identity, and once to use it for accessing the Customer-Managed-Key secret. @@ -1411,7 +1973,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1469,6 +2031,50 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = '' +// Non-required parameters +param blobServices = { + containers: [ + { + name: 'container' + publicAccess: 'None' + } + ] +} +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } +] +``` + +
    +

    + ### Example 9: _Using Customer-Managed-Keys with User-Assigned identity_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -1530,7 +2136,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1597,6 +2203,57 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssauacr001' +// Non-required parameters +param blobServices = { + containers: [ + { + name: 'container' + publicAccess: 'None' + } + ] +} +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + } +] +``` + +
    +

    + ### Example 10: _Deploying as Storage Account version 1_ This instance deploys the module as Storage Account version 1. @@ -1624,7 +2281,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1649,6 +2306,23 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssav1001' +// Non-required parameters +param kind = 'Storage' +param location = '' +``` + +
    +

    + ### Example 11: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1913,7 +2587,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2211,6 +2885,260 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/storage/storage-account:' + +// Required parameters +param name = 'ssawaf001' +// Non-required parameters +param allowBlobPublicAccess = false +param blobServices = { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + enableNfsV3AllSquash: true + enableNfsV3RootSquash: true + name: 'avdscripts' + publicAccess: 'None' + } + { + allowProtectedAppendWrites: false + enableWORM: true + metadata: { + testKey: 'testValue' + } + name: 'archivecontainer' + publicAccess: 'None' + WORMRetention: 666 + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + lastAccessTimeTrackingPolicyEnabled: true +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableHierarchicalNamespace = true +enableNfsV3: true +param enableSftp = true +param fileServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + shares: [ + { + accessTier: 'Hot' + name: 'avdprofiles' + shareQuota: 5120 + } + { + name: 'avdprofiles2' + shareQuota: 102400 + } + ] +} +param largeFileSharesState = 'Enabled' +param localUsers = [ + { + hasSharedKey: false + hasSshKey: true + hasSshPassword: false + homeDirectory: 'avdscripts' + name: 'testuser' + permissionScopes: [ + { + permissions: 'r' + resourceName: 'avdscripts' + service: 'blob' + } + ] + storageAccountName: 'ssawaf001' + } +] +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param managementPolicyRules = [ + { + definition: { + actions: { + baseBlob: { + delete: { + daysAfterModificationGreaterThan: 30 + } + tierToCool: { + daysAfterLastAccessTimeGreaterThan: 5 + } + } + } + filters: { + blobIndexMatch: [ + { + name: 'BlobIndex' + op: '==' + value: '1' + } + ] + blobTypes: [ + 'blockBlob' + ] + prefixMatch: [ + 'sample-container/log' + ] + } + } + enabled: true + name: 'FirstRule' + type: 'Lifecycle' + } +] +param networkAcls = { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '1.1.1.1' + } + ] + virtualNetworkRules: [ + { + action: 'Allow' + id: '' + } + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'blob' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param queueServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + queues: [ + { + metadata: { + key1: 'value1' + key2: 'value2' + } + name: 'queue1' + } + { + metadata: {} + name: 'queue2' + } + ] +} +param requireInfrastructureEncryption = true +param sasExpirationPeriod = '180.00:00:00' +param skuName = 'Standard_ZRS' +param tableServices = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + tables: [ + { + name: 'table1' + } + { + name: 'table2' + } + ] +} +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2255,7 +3183,7 @@ module storageAccount 'br/public:avm/res/storage/storage-account:' = { | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | | [`managementPolicyRules`](#parameter-managementpolicyrules) | array | The Storage Account ManagementPolicies Rules. | -| [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | Set the minimum TLS version on request to storage. | +| [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore. | | [`networkAcls`](#parameter-networkacls) | object | Networks ACLs, this value contains IPs to whitelist and/or Subnet information. If in use, bypass needs to be supplied. For security reasons, it is recommended to set the DefaultAction Deny. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | @@ -2730,7 +3658,7 @@ The Storage Account ManagementPolicies Rules. ### Parameter: `minimumTlsVersion` -Set the minimum TLS version on request to storage. +Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore. - Required: No - Type: string @@ -2738,9 +3666,8 @@ Set the minimum TLS version on request to storage. - Allowed: ```Bicep [ - 'TLS1_0' - 'TLS1_1' 'TLS1_2' + 'TLS1_3' ] ``` @@ -3134,6 +4061,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -3270,6 +4208,31 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Blob Data Contributor'` + - `'Storage Blob Data Owner'` + - `'Storage Blob Data Reader'` + - `'Storage Blob Delegator'` + - `'Storage File Data Privileged Contributor'` + - `'Storage File Data Privileged Reader'` + - `'Storage File Data SMB Share Contributor'` + - `'Storage File Data SMB Share Elevated Contributor'` + - `'Storage File Data SMB Share Reader'` + - `'Storage Queue Data Contributor'` + - `'Storage Queue Data Message Processor'` + - `'Storage Queue Data Message Sender'` + - `'Storage Queue Data Reader'` + - `'Storage Table Data Contributor'` + - `'Storage Table Data Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/blob-service/container/README.md b/avm/res/storage/storage-account/blob-service/container/README.md index 14d00393ef..34d861e3b5 100644 --- a/avm/res/storage/storage-account/blob-service/container/README.md +++ b/avm/res/storage/storage-account/blob-service/container/README.md @@ -34,6 +34,7 @@ This module deploys a Storage Account Blob Container. | Parameter | Type | Description | | :-- | :-- | :-- | +| [`blobServiceName`](#parameter-blobservicename) | string | The name of the parent Blob Service. Required if the template is used in a standalone deployment. | | [`defaultEncryptionScope`](#parameter-defaultencryptionscope) | string | Default the container to use specified encryption scope for all writes. | | [`denyEncryptionScopeOverride`](#parameter-denyencryptionscopeoverride) | bool | Block override of encryption scope from the container default. | | [`enableNfsV3AllSquash`](#parameter-enablenfsv3allsquash) | bool | Enable NFSv3 all squash on blob container. | @@ -59,6 +60,14 @@ The name of the parent Storage Account. Required if the template is used in a st - Required: Yes - Type: string +### Parameter: `blobServiceName` + +The name of the parent Blob Service. Required if the template is used in a standalone deployment. + +- Required: No +- Type: string +- Default: `'default'` + ### Parameter: `defaultEncryptionScope` Default the container to use specified encryption scope for all writes. @@ -144,6 +153,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Blob Data Contributor'` + - `'Storage Blob Data Owner'` + - `'Storage Blob Data Reader'` + - `'Storage Blob Delegator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json b/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json index e92ebe5e3f..1a92a67f27 100644 --- a/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json +++ b/avm/res/storage/storage-account/blob-service/container/immutability-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", diff --git a/avm/res/storage/storage-account/blob-service/container/main.bicep b/avm/res/storage/storage-account/blob-service/container/main.bicep index fa0193da72..9a19a6096f 100644 --- a/avm/res/storage/storage-account/blob-service/container/main.bicep +++ b/avm/res/storage/storage-account/blob-service/container/main.bicep @@ -6,6 +6,9 @@ metadata owner = 'Azure/module-maintainers' @description('Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment.') param storageAccountName string +@description('Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment.') +param blobServiceName string = 'default' + @description('Required. The name of the storage container to deploy.') param name string @@ -105,7 +108,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing name: storageAccountName resource blobServices 'blobServices@2022-09-01' existing = { - name: 'default' + name: blobServiceName } } diff --git a/avm/res/storage/storage-account/blob-service/container/main.json b/avm/res/storage/storage-account/blob-service/container/main.json index 98d00e679f..1144d31c91 100644 --- a/avm/res/storage/storage-account/blob-service/container/main.json +++ b/avm/res/storage/storage-account/blob-service/container/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1020003258393866601" + "version": "0.30.23.60470", + "templateHash": "7740343838101895320" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -95,6 +95,13 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, "name": { "type": "string", "metadata": { @@ -205,7 +212,7 @@ "existing": true, "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]", "dependsOn": [ "storageAccount" ] @@ -219,7 +226,7 @@ "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "properties": { "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", @@ -240,8 +247,8 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -288,8 +295,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", @@ -387,7 +394,7 @@ "metadata": { "description": "The resource ID of the deployed container." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", diff --git a/avm/res/storage/storage-account/blob-service/main.bicep b/avm/res/storage/storage-account/blob-service/main.bicep index c02c02f6fa..bb43c4d610 100644 --- a/avm/res/storage/storage-account/blob-service/main.bicep +++ b/avm/res/storage/storage-account/blob-service/main.bicep @@ -149,6 +149,7 @@ module blobServices_container 'container/main.bicep' = [ name: '${deployment().name}-Container-${index}' params: { storageAccountName: storageAccount.name + blobServiceName: blobServices.name name: container.name defaultEncryptionScope: container.?defaultEncryptionScope denyEncryptionScopeOverride: container.?denyEncryptionScopeOverride diff --git a/avm/res/storage/storage-account/blob-service/main.json b/avm/res/storage/storage-account/blob-service/main.json index 7531267468..6ab964fa85 100644 --- a/avm/res/storage/storage-account/blob-service/main.json +++ b/avm/res/storage/storage-account/blob-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17077763197163073998" + "version": "0.30.23.60470", + "templateHash": "12887537147730330940" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service.", @@ -365,6 +365,9 @@ "storageAccountName": { "value": "[parameters('storageAccountName')]" }, + "blobServiceName": { + "value": "[variables('name')]" + }, "name": { "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" }, @@ -403,8 +406,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1020003258393866601" + "version": "0.30.23.60470", + "templateHash": "7740343838101895320" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -493,6 +496,13 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, "name": { "type": "string", "metadata": { @@ -603,7 +613,7 @@ "existing": true, "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]", "dependsOn": [ "storageAccount" ] @@ -617,7 +627,7 @@ "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "properties": { "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", @@ -638,8 +648,8 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -686,8 +696,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", @@ -785,7 +795,7 @@ "metadata": { "description": "The resource ID of the deployed container." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", @@ -798,6 +808,7 @@ } }, "dependsOn": [ + "blobServices", "storageAccount" ] } diff --git a/avm/res/storage/storage-account/file-service/README.md b/avm/res/storage/storage-account/file-service/README.md index 3e9748cc67..af032effaa 100644 --- a/avm/res/storage/storage-account/file-service/README.md +++ b/avm/res/storage/storage-account/file-service/README.md @@ -13,7 +13,7 @@ This module deploys a Storage Account File Share Service. | Resource Type | API Version | | :-- | :-- | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/fileServices) | +| `Microsoft.Storage/storageAccounts/fileServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/fileServices) | | `Microsoft.Storage/storageAccounts/fileServices/shares` | [2023-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-01-01/storageAccounts/fileServices/shares) | ## Parameters diff --git a/avm/res/storage/storage-account/file-service/main.json b/avm/res/storage/storage-account/file-service/main.json index 9375230d2f..3e4af3b534 100644 --- a/avm/res/storage/storage-account/file-service/main.json +++ b/avm/res/storage/storage-account/file-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1933197013743223154" + "version": "0.30.23.60470", + "templateHash": "3657184950062156101" }, "name": "Storage Account File Share Services", "description": "This module deploys a Storage Account File Share Service.", @@ -286,8 +286,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13477688809575027800" + "version": "0.30.23.60470", + "templateHash": "5694394509785243538" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share.", @@ -493,8 +493,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10820882302387746924" + "version": "0.30.23.60470", + "templateHash": "11498628270290452072" } }, "parameters": { diff --git a/avm/res/storage/storage-account/file-service/share/main.json b/avm/res/storage/storage-account/file-service/share/main.json index 90dc220560..6f8f81b2dc 100644 --- a/avm/res/storage/storage-account/file-service/share/main.json +++ b/avm/res/storage/storage-account/file-service/share/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13477688809575027800" + "version": "0.30.23.60470", + "templateHash": "5694394509785243538" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share.", @@ -212,8 +212,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10820882302387746924" + "version": "0.30.23.60470", + "templateHash": "11498628270290452072" } }, "parameters": { diff --git a/avm/res/storage/storage-account/local-user/README.md b/avm/res/storage/storage-account/local-user/README.md index f8476f2e7a..b311040c23 100644 --- a/avm/res/storage/storage-account/local-user/README.md +++ b/avm/res/storage/storage-account/local-user/README.md @@ -12,7 +12,7 @@ This module deploys a Storage Account Local User, which is used for SFTP authent | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/localUsers) | +| `Microsoft.Storage/storageAccounts/localUsers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/localUsers) | ## Parameters diff --git a/avm/res/storage/storage-account/local-user/main.json b/avm/res/storage/storage-account/local-user/main.json index 3514e02614..8a19e11da9 100644 --- a/avm/res/storage/storage-account/local-user/main.json +++ b/avm/res/storage/storage-account/local-user/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18130658711251621530" + "version": "0.30.23.60470", + "templateHash": "14184905621772237225" }, "name": "Storage Account Local Users", "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", diff --git a/avm/res/storage/storage-account/main.bicep b/avm/res/storage/storage-account/main.bicep index 014c244abc..8e491ac177 100644 --- a/avm/res/storage/storage-account/main.bicep +++ b/avm/res/storage/storage-account/main.bicep @@ -114,11 +114,10 @@ param tableServices object = {} param allowBlobPublicAccess bool = false @allowed([ - 'TLS1_0' - 'TLS1_1' 'TLS1_2' + 'TLS1_3' ]) -@description('Optional. Set the minimum TLS version on request to storage.') +@description('Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore.') param minimumTlsVersion string = 'TLS1_2' @description('Conditional. If true, enables Hierarchical Namespace for the storage account. Required if enableSftp or enableNfsV3 is set to true.') @@ -341,7 +340,7 @@ resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentiti ) } -resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = { name: name location: location kind: kind @@ -413,7 +412,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { } : null supportsHttpsTrafficOnly: supportsHttpsTrafficOnly - isHnsEnabled: enableHierarchicalNamespace ? enableHierarchicalNamespace : null + isHnsEnabled: enableHierarchicalNamespace isSftpEnabled: enableSftp isNfsV3Enabled: enableNfsV3 ? enableNfsV3 : any('') largeFileSharesState: (skuName == 'Standard_LRS') || (skuName == 'Standard_ZRS') ? largeFileSharesState : null diff --git a/avm/res/storage/storage-account/main.json b/avm/res/storage/storage-account/main.json index 38e3f3d998..b6d1cc5d74 100644 --- a/avm/res/storage/storage-account/main.json +++ b/avm/res/storage/storage-account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6735651687082765200" + "version": "0.30.23.60470", + "templateHash": "7109049210516898074" }, "name": "Storage Accounts", "description": "This module deploys a Storage Account.", @@ -816,12 +816,11 @@ "type": "string", "defaultValue": "TLS1_2", "allowedValues": [ - "TLS1_0", - "TLS1_1", - "TLS1_2" + "TLS1_2", + "TLS1_3" ], "metadata": { - "description": "Optional. Set the minimum TLS version on request to storage." + "description": "Optional. Set the minimum TLS version on request to storage. The TLS versions 1.0 and 1.1 are deprecated and not supported anymore." } }, "enableHierarchicalNamespace": { @@ -1040,7 +1039,7 @@ }, "storageAccount": { "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", + "apiVersion": "2023-05-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -1064,7 +1063,7 @@ "accessTier": "[if(and(not(equals(parameters('kind'), 'Storage')), not(equals(parameters('kind'), 'BlockBlobStorage'))), parameters('accessTier'), null())]", "sasPolicy": "[if(not(empty(parameters('sasExpirationPeriod'))), createObject('expirationAction', 'Log', 'sasExpirationPeriod', parameters('sasExpirationPeriod')), null())]", "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]", - "isHnsEnabled": "[if(parameters('enableHierarchicalNamespace'), parameters('enableHierarchicalNamespace'), null())]", + "isHnsEnabled": "[parameters('enableHierarchicalNamespace')]", "isSftpEnabled": "[parameters('enableSftp')]", "isNfsV3Enabled": "[if(parameters('enableNfsV3'), parameters('enableNfsV3'), '')]", "largeFileSharesState": "[if(or(equals(parameters('skuName'), 'Standard_LRS'), equals(parameters('skuName'), 'Standard_ZRS')), parameters('largeFileSharesState'), null())]", @@ -1937,8 +1936,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11289787713365096902" + "version": "0.30.23.60470", + "templateHash": "16749766572958481061" }, "name": "Storage Account Management Policies", "description": "This module deploys a Storage Account Management Policy.", @@ -2047,8 +2046,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18130658711251621530" + "version": "0.30.23.60470", + "templateHash": "14184905621772237225" }, "name": "Storage Account Local Users", "description": "This module deploys a Storage Account Local User, which is used for SFTP authentication.", @@ -2265,8 +2264,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "17077763197163073998" + "version": "0.30.23.60470", + "templateHash": "12887537147730330940" }, "name": "Storage Account blob Services", "description": "This module deploys a Storage Account Blob Service.", @@ -2625,6 +2624,9 @@ "storageAccountName": { "value": "[parameters('storageAccountName')]" }, + "blobServiceName": { + "value": "[variables('name')]" + }, "name": { "value": "[coalesce(parameters('containers'), createArray())[copyIndex()].name]" }, @@ -2663,8 +2665,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1020003258393866601" + "version": "0.30.23.60470", + "templateHash": "7740343838101895320" }, "name": "Storage Account Blob Containers", "description": "This module deploys a Storage Account Blob Container.", @@ -2753,6 +2755,13 @@ "description": "Conditional. The name of the parent Storage Account. Required if the template is used in a standalone deployment." } }, + "blobServiceName": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the parent Blob Service. Required if the template is used in a standalone deployment." + } + }, "name": { "type": "string", "metadata": { @@ -2863,7 +2872,7 @@ "existing": true, "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]", + "name": "[format('{0}/{1}', parameters('storageAccountName'), parameters('blobServiceName'))]", "dependsOn": [ "storageAccount" ] @@ -2877,7 +2886,7 @@ "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", "apiVersion": "2022-09-01", - "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", + "name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", "properties": { "defaultEncryptionScope": "[if(not(empty(parameters('defaultEncryptionScope'))), parameters('defaultEncryptionScope'), null())]", "denyEncryptionScopeOverride": "[if(equals(parameters('denyEncryptionScopeOverride'), true()), parameters('denyEncryptionScopeOverride'), null())]", @@ -2898,8 +2907,8 @@ }, "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), 'default', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}/containers/{2}', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", "properties": { "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", @@ -2946,8 +2955,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7245741358008626948" + "version": "0.30.23.60470", + "templateHash": "17642721918788484059" }, "name": "Storage Account Blob Container Immutability Policies", "description": "This module deploys a Storage Account Blob Container Immutability Policy.", @@ -3045,7 +3054,7 @@ "metadata": { "description": "The resource ID of the deployed container." }, - "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), parameters('blobServiceName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", @@ -3058,6 +3067,7 @@ } }, "dependsOn": [ + "blobServices", "storageAccount" ] } @@ -3125,8 +3135,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1933197013743223154" + "version": "0.30.23.60470", + "templateHash": "3657184950062156101" }, "name": "Storage Account File Share Services", "description": "This module deploys a Storage Account File Share Service.", @@ -3406,8 +3416,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "13477688809575027800" + "version": "0.30.23.60470", + "templateHash": "5694394509785243538" }, "name": "Storage Account File Shares", "description": "This module deploys a Storage Account File Share.", @@ -3613,8 +3623,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "10820882302387746924" + "version": "0.30.23.60470", + "templateHash": "11498628270290452072" } }, "parameters": { @@ -3889,8 +3899,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9552908737955027812" + "version": "0.30.23.60470", + "templateHash": "6947504466788447852" }, "name": "Storage Account Queue Services", "description": "This module deploys a Storage Account Queue Service.", @@ -4134,8 +4144,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1992900679572007532" + "version": "0.30.23.60470", + "templateHash": "6090221832347220924" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue.", @@ -4405,8 +4415,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15143318143658591417" + "version": "0.30.23.60470", + "templateHash": "6657632516379685259" }, "name": "Storage Account Table Services", "description": "This module deploys a Storage Account Table Service.", @@ -4647,8 +4657,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16017327978473583176" + "version": "0.30.23.60470", + "templateHash": "7397003163362434404" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table.", @@ -4895,7 +4905,7 @@ "value": "[last(split(coalesce(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '//'), '/'))]" }, "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey1, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString1, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[0].value))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey2, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString2, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2022-09-01').keys[1].value))), createArray()))]" + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey1, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[0].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString1'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString1, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[0].value))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2'), createArray(createObject('name', parameters('secretsExportConfiguration').accessKey2, 'value', listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[1].value)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'connectionString2'), createArray(createObject('name', parameters('secretsExportConfiguration').connectionString2, 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix=core.windows.net', parameters('name'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('name')), '2023-05-01').keys[1].value))), createArray()))]" } }, "template": { @@ -4905,8 +4915,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "986606208324987345" + "version": "0.30.23.60470", + "templateHash": "12263717469683062316" } }, "definitions": { @@ -5047,14 +5057,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('storageAccount', '2023-05-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('storageAccount', '2022-09-01', 'full').location]" + "value": "[reference('storageAccount', '2023-05-01', 'full').location]" }, "serviceEndpoints": { "type": "object", @@ -5087,4 +5097,4 @@ "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" } } -} \ No newline at end of file +} diff --git a/avm/res/storage/storage-account/management-policy/main.json b/avm/res/storage/storage-account/management-policy/main.json index c348d69daf..6acd0abce6 100644 --- a/avm/res/storage/storage-account/management-policy/main.json +++ b/avm/res/storage/storage-account/management-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "11289787713365096902" + "version": "0.30.23.60470", + "templateHash": "16749766572958481061" }, "name": "Storage Account Management Policies", "description": "This module deploys a Storage Account Management Policy.", diff --git a/avm/res/storage/storage-account/queue-service/README.md b/avm/res/storage/storage-account/queue-service/README.md index ce773dbe3d..94ce2dacff 100644 --- a/avm/res/storage/storage-account/queue-service/README.md +++ b/avm/res/storage/storage-account/queue-service/README.md @@ -14,8 +14,8 @@ This module deploys a Storage Account Queue Service. | :-- | :-- | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/queueServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | ## Parameters diff --git a/avm/res/storage/storage-account/queue-service/main.json b/avm/res/storage/storage-account/queue-service/main.json index 00065e2abe..6fc76d0b47 100644 --- a/avm/res/storage/storage-account/queue-service/main.json +++ b/avm/res/storage/storage-account/queue-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "9552908737955027812" + "version": "0.30.23.60470", + "templateHash": "6947504466788447852" }, "name": "Storage Account Queue Services", "description": "This module deploys a Storage Account Queue Service.", @@ -250,8 +250,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1992900679572007532" + "version": "0.30.23.60470", + "templateHash": "6090221832347220924" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue.", diff --git a/avm/res/storage/storage-account/queue-service/queue/README.md b/avm/res/storage/storage-account/queue-service/queue/README.md index 508062614a..140ca97388 100644 --- a/avm/res/storage/storage-account/queue-service/queue/README.md +++ b/avm/res/storage/storage-account/queue-service/queue/README.md @@ -13,7 +13,7 @@ This module deploys a Storage Account Queue. | Resource Type | API Version | | :-- | :-- | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/queueServices/queues) | +| `Microsoft.Storage/storageAccounts/queueServices/queues` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/queueServices/queues) | ## Parameters @@ -64,6 +64,20 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Queue Data Contributor'` + - `'Storage Queue Data Message Processor'` + - `'Storage Queue Data Message Sender'` + - `'Storage Queue Data Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/queue-service/queue/main.json b/avm/res/storage/storage-account/queue-service/queue/main.json index 8bea12f90e..2aad9fefb2 100644 --- a/avm/res/storage/storage-account/queue-service/queue/main.json +++ b/avm/res/storage/storage-account/queue-service/queue/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1992900679572007532" + "version": "0.30.23.60470", + "templateHash": "6090221832347220924" }, "name": "Storage Account Queues", "description": "This module deploys a Storage Account Queue.", diff --git a/avm/res/storage/storage-account/table-service/README.md b/avm/res/storage/storage-account/table-service/README.md index f4a529a253..7f65d890d0 100644 --- a/avm/res/storage/storage-account/table-service/README.md +++ b/avm/res/storage/storage-account/table-service/README.md @@ -14,8 +14,8 @@ This module deploys a Storage Account Table Service. | :-- | :-- | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `Microsoft.Storage/storageAccounts/tableServices` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | ## Parameters diff --git a/avm/res/storage/storage-account/table-service/main.json b/avm/res/storage/storage-account/table-service/main.json index 5582b11c4a..df8cac0dbd 100644 --- a/avm/res/storage/storage-account/table-service/main.json +++ b/avm/res/storage/storage-account/table-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15143318143658591417" + "version": "0.30.23.60470", + "templateHash": "6657632516379685259" }, "name": "Storage Account Table Services", "description": "This module deploys a Storage Account Table Service.", @@ -247,8 +247,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16017327978473583176" + "version": "0.30.23.60470", + "templateHash": "7397003163362434404" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table.", diff --git a/avm/res/storage/storage-account/table-service/table/README.md b/avm/res/storage/storage-account/table-service/table/README.md index dfe48226f8..63e5d835bf 100644 --- a/avm/res/storage/storage-account/table-service/table/README.md +++ b/avm/res/storage/storage-account/table-service/table/README.md @@ -13,7 +13,7 @@ This module deploys a Storage Account Table. | Resource Type | API Version | | :-- | :-- | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | -| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/storageAccounts/tableServices/tables) | +| `Microsoft.Storage/storageAccounts/tableServices/tables` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Storage/2023-04-01/storageAccounts/tableServices/tables) | ## Parameters @@ -55,6 +55,18 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Reader and Data Access'` + - `'Role Based Access Control Administrator'` + - `'Storage Account Backup Contributor'` + - `'Storage Account Contributor'` + - `'Storage Account Key Operator Service Role'` + - `'Storage Table Data Contributor'` + - `'Storage Table Data Reader'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/storage/storage-account/table-service/table/main.json b/avm/res/storage/storage-account/table-service/table/main.json index 0476ee247e..15dc63d03b 100644 --- a/avm/res/storage/storage-account/table-service/table/main.json +++ b/avm/res/storage/storage-account/table-service/table/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "16017327978473583176" + "version": "0.30.23.60470", + "templateHash": "7397003163362434404" }, "name": "Storage Account Table", "description": "This module deploys a Storage Account Table.", diff --git a/avm/res/storage/storage-account/version.json b/avm/res/storage/storage-account/version.json index 291fb73e82..35d09f6dbf 100644 --- a/avm/res/storage/storage-account/version.json +++ b/avm/res/storage/storage-account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.13", + "version": "0.14", "pathFilters": [ "./main.json" ] diff --git a/avm/res/synapse/private-link-hub/README.md b/avm/res/synapse/private-link-hub/README.md index 6b406c9bd6..d0dba94113 100644 --- a/avm/res/synapse/private-link-hub/README.md +++ b/avm/res/synapse/private-link-hub/README.md @@ -64,7 +64,7 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -86,6 +86,22 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/private-link-hub:' + +// Required parameters +param name = 'splhmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -162,7 +178,7 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -242,6 +258,72 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/private-link-hub:' + +// Required parameters +param name = 'splhmax001' +// Non-required parameters +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '049a8b5a-70dc-4749-965c-b009733cf432' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Reader' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c' + } +] +param tags = { + 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. @@ -291,7 +373,7 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -340,6 +422,45 @@ module privateLinkHub 'br/public:avm/res/synapse/private-link-hub:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/private-link-hub:' + +// Required parameters +param name = 'splhwaf001' +// Non-required parameters +param location = '' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Web' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -708,6 +829,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -819,6 +951,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/synapse/workspace/README.md b/avm/res/synapse/workspace/README.md index d9b6a461a3..5e52048a3a 100644 --- a/avm/res/synapse/workspace/README.md +++ b/avm/res/synapse/workspace/README.md @@ -77,7 +77,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -108,6 +108,25 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swmin001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using encryption with Customer-Managed-Key_ This instance deploys the module using Customer-Managed-Keys using a System-Assigned Identity to access the Customer-Managed-Key secret. @@ -142,7 +161,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -182,6 +201,30 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swensa001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' +} +param encryptionActivateWorkspace = true +param location = '' +``` + +
    +

    + ### Example 3: _Using encryption with Customer-Managed-Key_ This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. @@ -216,7 +259,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -254,6 +297,30 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swenua001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param location = '' +``` + +
    +

    + ### Example 4: _Using firewall rules_ This instance deploys the module with the configuration of firewall rules. @@ -295,7 +362,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -340,6 +407,37 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swfwr001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param firewallRules = [ + { + endIpAddress: '87.14.134.20' + name: 'fwrule01' + startIpAddress: '87.14.134.20' + } + { + endIpAddress: '87.14.134.22' + name: 'fwrule02' + startIpAddress: '87.14.134.21' + } +] +param location = '' +``` + +
    +

    + ### Example 5: _Using managed Vnet_ This instance deploys the module using a managed Vnet. @@ -374,7 +472,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -416,6 +514,30 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swmanv001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param allowedAadTenantIdsForLinking = [ + '' +] +param location = '' +param managedVirtualNetwork = true +param preventDataExfiltration = true +``` + +
    +

    + ### Example 6: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -560,7 +682,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -722,6 +844,140 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swmax001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param administrator = { + administratorType: 'ServicePrincipal' + login: 'dep-msi-swmax' + sid: '' +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'SynapseRbacOperations' + } + { + category: 'SynapseLinkEvent' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param initialWorkspaceAdminObjectID = '' +param integrationRuntimes = [ + { + name: 'shir01' + type: 'SelfHosted' + } +] +param location = '' +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param managedVirtualNetwork = true +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SQL' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SQL' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SqlOnDemand' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'Dev' + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '499f9243-2170-4204-807d-ee6d0f94a0d0' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +``` + +
    +

    + ### Example 7: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -798,7 +1054,7 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -886,6 +1142,72 @@ module workspace 'br/public:avm/res/synapse/workspace:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/synapse/workspace:' + +// Required parameters +param defaultDataLakeStorageAccountResourceId = '' +param defaultDataLakeStorageFilesystem = '' +param name = 'swwaf001' +param sqlAdministratorLogin = 'synwsadmin' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'SynapseRbacOperations' + } + { + category: 'SynapseLinkEvent' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param integrationRuntimes = [ + { + name: 'shir01' + type: 'SelfHosted' + } +] +param location = '' +param managedVirtualNetwork = true +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + service: 'SQL' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -1651,6 +1973,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1778,6 +2111,13 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Resource Policy Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/virtual-machine-images/image-template/README.md b/avm/res/virtual-machine-images/image-template/README.md index 022c56722c..22bfaaa10a 100644 --- a/avm/res/virtual-machine-images/image-template/README.md +++ b/avm/res/virtual-machine-images/image-template/README.md @@ -17,7 +17,7 @@ This module deploys a Virtual Machine Image Template that can be consumed by Azu | :-- | :-- | | `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.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/imageTemplates) | +| `Microsoft.VirtualMachineImages/imageTemplates` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.VirtualMachineImages/2023-07-01/imageTemplates) | ## Usage examples @@ -75,7 +75,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -121,6 +121,40 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/virtual-machine-images/image-template:' + +// Required parameters +param distributions = [ + { + imageName: 'mi-vmiitmin-001' + type: 'ManagedImage' + } +] +param imageSource = { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-23h2-ent' + type: 'PlatformImage' + version: 'latest' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param name = 'vmiitmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -247,7 +281,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -399,6 +433,122 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/virtual-machine-images/image-template:' + +// Required parameters +param distributions = [ + { + imageName: 'mi-vmiitmax-001' + type: 'ManagedImage' + } + { + imageName: 'umi-vmiitmax-001' + type: 'VHD' + } + { + replicationRegions: [ + '' + ] + sharedImageGalleryImageDefinitionResourceId: '' + sharedImageGalleryImageDefinitionTargetVersion: '' + type: 'SharedImage' + } +] +param imageSource = { + offer: 'ubuntu-24_04-lts' + publisher: 'canonical' + sku: 'server' + type: 'PlatformImage' + version: 'latest' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param name = 'vmiitmax001' +// Non-required parameters +param buildTimeoutInMinutes = 60 +param customizationSteps = [ + { + name: 'PowerShell installation' + scriptUri: '' + type: 'Shell' + } + { + destination: 'Initialize-LinuxSoftware.ps1' + name: 'Initialize-LinuxSoftware' + sourceUri: '' + type: 'File' + } + { + inline: [ + 'pwsh \'Initialize-LinuxSoftware.ps1\'' + ] + name: 'Software installation' + type: 'Shell' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param optimizeVmBoot = 'Enabled' +param osDiskSizeGB = 127 +param roleAssignments = [ + { + name: 'bb257a92-dc06-4831-9b74-ee5442d8ce0f' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param stagingResourceGroupResourceId = '' +param subnetResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param validationProcess = { + continueDistributeOnFailure: true + inVMValidations: [ + { + inline: [ + 'echo \'Software validation successful.\'' + ] + name: 'Validate-Software' + type: 'Shell' + } + ] + sourceValidationOnly: false +} +param vmSize = 'Standard_D2s_v3' +param vmUserAssignedIdentities = [ + '' +] +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -455,7 +605,7 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template: -

    via JSON Parameter file +via JSON parameters file ```json { @@ -519,6 +669,52 @@ module imageTemplate 'br/public:avm/res/virtual-machine-images/image-template:

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/virtual-machine-images/image-template:' + +// Required parameters +param distributions = [ + { + sharedImageGalleryImageDefinitionResourceId: '' + type: 'SharedImage' + } +] +param imageSource = { + offer: 'Windows-11' + publisher: 'MicrosoftWindowsDesktop' + sku: 'win11-22h2-avd' + type: 'PlatformImage' + version: 'latest' +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param name = 'vmiitwaf001' +// Non-required parameters +param customizationSteps = [ + { + restartTimeout: '10m' + type: 'WindowsRestart' + } +] +param location = '' +param subnetResourceId = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -691,6 +887,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/web/connection/README.md b/avm/res/web/connection/README.md index 8c29f78a19..a192ce132b 100644 --- a/avm/res/web/connection/README.md +++ b/avm/res/web/connection/README.md @@ -65,7 +65,7 @@ module connection 'br/public:avm/res/web/connection:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -95,6 +95,26 @@ module connection 'br/public:avm/res/web/connection:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/connection:' + +// Required parameters +param displayName = 'azuremonitorlogs' +param name = 'azuremonitor' +// Non-required parameters +param api = { + id: '' +} +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -153,7 +173,7 @@ module connection 'br/public:avm/res/web/connection:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -217,6 +237,54 @@ module connection 'br/public:avm/res/web/connection:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/connection:' + +// Required parameters +param displayName = 'azuremonitorlogs' +param name = 'azuremonitor' +// Non-required parameters +param api = { + id: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param roleAssignments = [ + { + name: '396667c8-de54-4dcb-916a-72af71359f34' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 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. @@ -252,7 +320,7 @@ module connection 'br/public:avm/res/web/connection:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -289,6 +357,31 @@ module connection 'br/public:avm/res/web/connection:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/connection:' + +// Required parameters +param displayName = 'azuremonitorlogs' +param name = 'azuremonitor' +// Non-required parameters +param api = { + id: '' +} +param location = '' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -460,6 +553,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/web/hosting-environment/README.md b/avm/res/web/hosting-environment/README.md index c6aa44fb42..d47314ce86 100644 --- a/avm/res/web/hosting-environment/README.md +++ b/avm/res/web/hosting-environment/README.md @@ -60,7 +60,7 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -88,6 +88,24 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/hosting-environment:' + +// Required parameters +param name = 'whemin001' +param subnetResourceId = '' +// Non-required parameters +param kind = 'ASEv3' +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -171,7 +189,7 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -282,6 +300,79 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/hosting-environment:' + +// Required parameters +param name = 'whemax001' +param subnetResourceId = '' +// Non-required parameters +param allowNewPrivateEndpointConnections = true +param clusterSettings = [ + { + name: 'DisableTls1.0' + value: '1' + } +] +param customDnsSuffix = 'internal.contoso.com' +param customDnsSuffixCertificateUrl = '' +param customDnsSuffixKeyVaultReferenceIdentity = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param ftpEnabled = true +param inboundIpAddressOverride = '10.0.0.10' +param internalLoadBalancingMode = 'Web, Publishing' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param remoteDebugEnabled = true +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param tags = { + 'hidden-title': 'This is visible in the resource name' + hostingEnvironmentName: 'whemax001' + resourceType: 'App Service Environment' +} +param upgradePreference = 'Late' +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -344,7 +435,7 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

    -via JSON Parameter file +via JSON parameters file ```json { @@ -430,6 +521,58 @@ module hostingEnvironment 'br/public:avm/res/web/hosting-environment:'

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/hosting-environment:' + +// Required parameters +param name = 'whewaf001' +param subnetResourceId = '' +// Non-required parameters +param allowNewPrivateEndpointConnections = true +param clusterSettings = [ + { + name: 'DisableTls1.0' + value: '1' + } +] +param customDnsSuffix = 'internal.contoso.com' +param customDnsSuffixCertificateUrl = '' +param customDnsSuffixKeyVaultReferenceIdentity = '' +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param ftpEnabled = true +param inboundIpAddressOverride = '10.0.0.10' +param internalLoadBalancingMode = 'Web, Publishing' +param location = '' +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param remoteDebugEnabled = true +param tags = { + 'hidden-title': 'This is visible in the resource name' + hostingEnvironmentName: 'whewaf001' + resourceType: 'App Service Environment' +} +param upgradePreference = 'Late' +``` + +
    +

    + ## Parameters **Required parameters** @@ -797,6 +940,12 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` + - `'User Access Administrator'` **Required parameters** diff --git a/avm/res/web/serverfarm/README.md b/avm/res/web/serverfarm/README.md index 9683316417..eb15593b7c 100644 --- a/avm/res/web/serverfarm/README.md +++ b/avm/res/web/serverfarm/README.md @@ -46,8 +46,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { params: { // Required parameters name: 'wsfmin001' - skuCapacity: 2 - skuName: 'S1' // Non-required parameters location: '' } @@ -59,7 +57,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -70,12 +68,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": { "value": "wsfmin001" }, - "skuCapacity": { - "value": 2 - }, - "skuName": { - "value": "S1" - }, // Non-required parameters "location": { "value": "" @@ -87,6 +79,22 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/serverfarm:' + +// Required parameters +param name = 'wsfmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -102,8 +110,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { params: { // Required parameters name: 'wsfmax001' - skuCapacity: 1 - skuName: 'S1' // Non-required parameters diagnosticSettings: [ { @@ -143,12 +149,14 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { roleDefinitionIdOrName: '' } ] + skuCapacity: 3 + skuName: 'P1v3' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - zoneRedundant: false + zoneRedundant: true } } ``` @@ -158,7 +166,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -169,12 +177,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": { "value": "wsfmax001" }, - "skuCapacity": { - "value": 1 - }, - "skuName": { - "value": "S1" - }, // Non-required parameters "diagnosticSettings": { "value": [ @@ -226,6 +228,12 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { } ] }, + "skuCapacity": { + "value": 3 + }, + "skuName": { + "value": "P1v3" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -234,7 +242,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { } }, "zoneRedundant": { - "value": false + "value": true } } } @@ -243,6 +251,67 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/serverfarm:' + +// Required parameters +param name = 'wsfmax001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingwsfmax' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param kind = 'App' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param perSiteScaling = true +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuCapacity = 3 +param skuName = 'P1v3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneRedundant = true +``` + +
    +

    + ### Example 3: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. Note - whilst this test is WAF aligned, zoneRedundant is set to false to avoid temporary AVM environment challenges. It is highly recommended that users of this module set the property value to true. @@ -258,8 +327,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { params: { // Required parameters name: 'wsfwaf001' - skuCapacity: 2 - skuName: 'P1v3' // Non-required parameters diagnosticSettings: [ { @@ -281,12 +348,14 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { kind: 'CanNotDelete' name: 'lock' } + skuCapacity: 3 + skuName: 'P1v3' tags: { Environment: 'Non-Prod' 'hidden-title': 'This is visible in the resource name' Role: 'DeploymentValidation' } - zoneRedundant: false + zoneRedundant: true } } ``` @@ -296,7 +365,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -307,12 +376,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": { "value": "wsfwaf001" }, - "skuCapacity": { - "value": 2 - }, - "skuName": { - "value": "P1v3" - }, // Non-required parameters "diagnosticSettings": { "value": [ @@ -342,6 +405,12 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { "name": "lock" } }, + "skuCapacity": { + "value": 3 + }, + "skuName": { + "value": "P1v3" + }, "tags": { "value": { "Environment": "Non-Prod", @@ -350,7 +419,7 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { } }, "zoneRedundant": { - "value": false + "value": true } } } @@ -359,6 +428,49 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/serverfarm:' + +// Required parameters +param name = 'wsfwaf001' +// Non-required parameters +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingwsfwaf' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param kind = 'App' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'lock' +} +param skuCapacity = 3 +param skuName = 'P1v3' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zoneRedundant = true +``` + +
    +

    + ## Parameters **Required parameters** @@ -366,8 +478,6 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { | Parameter | Type | Description | | :-- | :-- | :-- | | [`name`](#parameter-name) | string | Name of the app service plan. | -| [`skuCapacity`](#parameter-skucapacity) | int | Number of workers associated with the App Service Plan. | -| [`skuName`](#parameter-skuname) | string | The name of the SKU will Determine the tier, size, family of the App Service Plan. | **Conditional parameters** @@ -389,6 +499,8 @@ module serverfarm 'br/public:avm/res/web/serverfarm:' = { | [`maximumElasticWorkerCount`](#parameter-maximumelasticworkercount) | int | Maximum number of total workers allowed for this ElasticScaleEnabled App Service Plan. | | [`perSiteScaling`](#parameter-persitescaling) | bool | If true, apps assigned to this App Service plan can be scaled independently. If false, apps assigned to this App Service plan will scale to all instances of the plan. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuCapacity`](#parameter-skucapacity) | int | Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones. | +| [`skuName`](#parameter-skuname) | string | The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`targetWorkerCount`](#parameter-targetworkercount) | int | Scaling worker count. | | [`targetWorkerSize`](#parameter-targetworkersize) | int | The instance size of the hosting plan (small, medium, or large). | @@ -402,27 +514,6 @@ Name of the app service plan. - Required: Yes - Type: string -### Parameter: `skuCapacity` - -Number of workers associated with the App Service Plan. - -- Required: Yes -- Type: int - -### Parameter: `skuName` - -The name of the SKU will Determine the tier, size, family of the App Service Plan. - -- Required: Yes -- Type: string -- Example: - ```Bicep - 'F1' - 'B1' - 'P1v3' - 'I1v2' - ``` - ### Parameter: `reserved` Defaults to false when creating Windows/app App Service Plan. Required if creating a Linux App Service Plan and must be set to true. @@ -648,6 +739,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** @@ -731,6 +830,30 @@ The principal type of the assigned principal ID. ] ``` +### Parameter: `skuCapacity` + +Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones. + +- Required: No +- Type: int +- Default: `3` + +### Parameter: `skuName` + +The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones. + +- Required: No +- Type: string +- Default: `'P1v3'` +- Example: + ```Bicep + 'F1' + 'B1' + 'P1v3' + 'I1v2' + 'FC1' + ``` + ### Parameter: `tags` Tags of the resource. diff --git a/avm/res/web/serverfarm/main.bicep b/avm/res/web/serverfarm/main.bicep index cd823f28ce..3d04b2f664 100644 --- a/avm/res/web/serverfarm/main.bicep +++ b/avm/res/web/serverfarm/main.bicep @@ -7,19 +7,20 @@ metadata owner = 'Azure/module-maintainers' @maxLength(60) param name string -@description('Required. The name of the SKU will Determine the tier, size, family of the App Service Plan.') +@description('Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones.') @metadata({ example: ''' 'F1' 'B1' 'P1v3' 'I1v2' + 'FC1' ''' }) -param skuName string +param skuName string = 'P1v3' -@description('Required. Number of workers associated with the App Service Plan.') -param skuCapacity int +@description('Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones.') +param skuCapacity int = 3 @description('Optional. Location for all resources.') param location string = resourceGroup().location @@ -129,7 +130,8 @@ resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = { tags: tags sku: { name: skuName - capacity: skuCapacity + capacity: skuName == 'FC1' ? null : skuCapacity + tier: skuName == 'FC1' ? 'FlexConsumption' : null } properties: { workerTierName: workerTierName @@ -185,11 +187,12 @@ resource appServicePlan_roleAssignments 'Microsoft.Authorization/roleAssignments for (roleAssignment, index) in (roleAssignments ?? []): { name: guid(appServicePlan.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) + roleDefinitionId: 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 diff --git a/avm/res/web/serverfarm/main.json b/avm/res/web/serverfarm/main.json index 68729b8033..e6d8dd5be3 100644 --- a/avm/res/web/serverfarm/main.json +++ b/avm/res/web/serverfarm/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16609348340052214807" + "version": "0.30.23.60470", + "templateHash": "489102920669919211" }, "name": "App Service Plan", "description": "This module deploys an App Service Plan.", @@ -203,15 +203,17 @@ }, "skuName": { "type": "string", + "defaultValue": "P1v3", "metadata": { - "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n ", - "description": "Required. The name of the SKU will Determine the tier, size, family of the App Service Plan." + "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n 'FC1'\n ", + "description": "Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones." } }, "skuCapacity": { "type": "int", + "defaultValue": 3, "metadata": { - "description": "Required. Number of workers associated with the App Service Plan." + "description": "Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones." } }, "location": { @@ -377,7 +379,8 @@ "tags": "[parameters('tags')]", "sku": { "name": "[parameters('skuName')]", - "capacity": "[parameters('skuCapacity')]" + "capacity": "[if(equals(parameters('skuName'), 'FC1'), null(), parameters('skuCapacity'))]", + "tier": "[if(equals(parameters('skuName'), 'FC1'), 'FlexConsumption', null())]" }, "properties": { "workerTierName": "[parameters('workerTierName')]", @@ -447,7 +450,7 @@ "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", "name": "[guid(resourceId('Microsoft.Web/serverfarms', 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)))]", + "roleDefinitionId": "[coalesce(tryGet(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')]", diff --git a/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep index 1de03468ef..afb9a3ac26 100644 --- a/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/defaults/main.test.bicep @@ -18,7 +18,7 @@ param serviceShort string = 'wsfmin' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var enforcedLocation = 'eastus' +var enforcedLocation = 'australiaeast' // ============ // // Dependencies // @@ -43,8 +43,6 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: enforcedLocation - skuName: 'S1' - skuCapacity: 2 } } ] diff --git a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep index b5d2046b5f..7b0bd49b7c 100644 --- a/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/max/main.test.bicep @@ -18,7 +18,7 @@ param serviceShort string = 'wsfmax' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var enforcedLocation = 'eastus' +var enforcedLocation = 'australiaeast' // ============ // // Dependencies // @@ -64,10 +64,10 @@ module testDeployment '../../../main.bicep' = [ params: { name: '${namePrefix}${serviceShort}001' location: enforcedLocation - skuName: 'S1' - skuCapacity: 1 + skuName: 'P1v3' + skuCapacity: 3 perSiteScaling: true - zoneRedundant: false + zoneRedundant: true kind: 'App' lock: { name: 'lock' diff --git a/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep b/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep index 15eb7e25be..3e0e62dd53 100644 --- a/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/web/serverfarm/tests/e2e/waf-aligned/main.test.bicep @@ -18,7 +18,7 @@ param serviceShort string = 'wsfwaf' param namePrefix string = '#_namePrefix_#' #disable-next-line no-hardcoded-location // Just a value to avoid ongoing capacity challenges -var enforcedLocation = 'eastus' +var enforcedLocation = 'australiaeast' // ============ // // Dependencies // @@ -56,8 +56,8 @@ module testDeployment '../../../main.bicep' = [ name: '${namePrefix}${serviceShort}001' location: enforcedLocation skuName: 'P1v3' - skuCapacity: 2 - zoneRedundant: false + skuCapacity: 3 + zoneRedundant: true kind: 'App' lock: { name: 'lock' diff --git a/avm/res/web/site/README.md b/avm/res/web/site/README.md index 5b72d460f5..449f709e49 100644 --- a/avm/res/web/site/README.md +++ b/avm/res/web/site/README.md @@ -21,12 +21,13 @@ This module deploys a Web or Function App. | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | -| `Microsoft.Web/sites` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites) | +| `Microsoft.Web/sites` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | +| `Microsoft.Web/sites/config` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/extensions` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/extensions) | | `Microsoft.Web/sites/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/hybridConnectionNamespaces/relays) | -| `Microsoft.Web/sites/slots` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots) | +| `Microsoft.Web/sites/slots` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/slots) | | `Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots/hybridConnectionNamespaces/relays) | @@ -41,15 +42,16 @@ The following section provides usage examples for the module, which were used to - [Function App, using only defaults](#example-1-function-app-using-only-defaults) - [Function App, using large parameter set](#example-2-function-app-using-large-parameter-set) -- [Web App, using only defaults](#example-3-web-app-using-only-defaults) -- [Web App](#example-4-web-app) -- [WAF-aligned](#example-5-waf-aligned) -- [Web App, using only defaults](#example-6-web-app-using-only-defaults) -- [Web App, using large parameter set](#example-7-web-app-using-large-parameter-set) -- [Web App, using only defaults](#example-8-web-app-using-only-defaults) -- [Web App, using large parameter set](#example-9-web-app-using-large-parameter-set) -- [Web App](#example-10-web-app) -- [Windows Web App for Containers, using only defaults](#example-11-windows-web-app-for-containers-using-only-defaults) +- [Function App, using only defaults](#example-3-function-app-using-only-defaults) +- [Web App, using only defaults](#example-4-web-app-using-only-defaults) +- [Web App](#example-5-web-app) +- [WAF-aligned](#example-6-waf-aligned) +- [Web App, using only defaults](#example-7-web-app-using-only-defaults) +- [Web App, using large parameter set](#example-8-web-app-using-large-parameter-set) +- [Web App, using only defaults](#example-9-web-app-using-only-defaults) +- [Web App, using large parameter set](#example-10-web-app-using-large-parameter-set) +- [Web App](#example-11-web-app) +- [Windows Web App for Containers, using only defaults](#example-12-windows-web-app-for-containers-using-only-defaults) ### Example 1: _Function App, using only defaults_ @@ -79,7 +81,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -107,6 +109,24 @@ module site 'br/public:avm/res/web/site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'functionapp' +param name = 'wsfamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Function App, using large parameter set_ This instance deploys the module as Function App with most of its features enabled. @@ -297,7 +317,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -515,7 +535,278 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 3: _Web App, using only defaults_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'functionapp' +param name = 'wsfamax001' +param serverFarmResourceId = '' +// Non-required parameters +param appInsightResourceId = '' +param appSettingsKeyValuePairs = { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + EASYAUTH_SECRET: '' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' +} +authSettingV2Configuration: { + globalValidation: { + requireAuthentication: true + unauthenticatedClientAction: 'Return401' + } + httpSettings: { + forwardProxy: { + convention: 'NoProxy' + } + requireHttps: true + routes: { + apiPrefix: '/.auth' + } + } + identityProviders: { + azureActiveDirectory: { + enabled: true + login: { + disableWWWAuthenticate: false + } + registration: { + clientId: 'd874dd2f-2032-4db1-a053-f0ec243685aa' + clientSecretSettingName: 'EASYAUTH_SECRET' + openIdIssuer: '' + } + validation: { + allowedAudiences: [ + 'api://d874dd2f-2032-4db1-a053-f0ec243685aa' + ] + defaultAuthorizationPolicy: { + allowedPrincipals: {} + } + jwtClaimChecks: {} + } + } + } + login: { + allowedExternalRedirectUrls: [ + 'string' + ] + cookieExpiration: { + convention: 'FixedTime' + timeToExpiration: '08:00:00' + } + nonce: { + nonceExpirationInterval: '00:05:00' + validateNonce: true + } + preserveUrlFragmentsForLogins: false + routes: {} + tokenStore: { + azureBlobStorage: {} + enabled: true + fileSystem: {} + tokenRefreshExtensionHours: 72 + } + } + platform: { + enabled: true + runtimeVersion: '~1' + } +} +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param hybridConnectionRelays = [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } +] +param keyVaultAccessIdentityResourceId = '' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: '9efc9c10-f482-4af0-9acb-03b5a16f947e' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param siteConfig = { + alwaysOn: true + use32BitWorkerProcess: false +} +param storageAccountResourceId = '' +param storageAccountUseIdentityAuthentication = true +``` + +
    +

    + +### Example 3: _Function App, using only defaults_ + +This instance deploys the module as Function App with the minimum set of required parameters. + + +

    + +via Bicep module + +```bicep +module site 'br/public:avm/res/web/site:' = { + name: 'siteDeployment' + params: { + // Required parameters + kind: 'functionapp' + name: 'wsfaset001' + serverFarmResourceId: '' + // Non-required parameters + appSettingsKeyValuePairs: { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' + } + location: '' + } +} +``` + +
    +

    + +

    + +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "kind": { + "value": "functionapp" + }, + "name": { + "value": "wsfaset001" + }, + "serverFarmResourceId": { + "value": "" + }, + // Non-required parameters + "appSettingsKeyValuePairs": { + "value": { + "AzureFunctionsJobHost__logging__logLevel__default": "Trace", + "FUNCTIONS_EXTENSION_VERSION": "~4", + "FUNCTIONS_WORKER_RUNTIME": "dotnet" + } + }, + "location": { + "value": "" + } + } +} +``` + +
    +

    + +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'functionapp' +param name = 'wsfaset001' +param serverFarmResourceId = '' +// Non-required parameters +param appSettingsKeyValuePairs = { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' +} +param location = '' +``` + +
    +

    + +### Example 4: _Web App, using only defaults_ This instance deploys the module as a Linux Web App with the minimum set of required parameters. @@ -552,7 +843,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -591,7 +882,34 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 4: _Web App_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,linux,container' +param name = 'wslwamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +param siteConfig = { + appSettings: [ + { + name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' + value: 'false' + } + ] + linuxFxVersion: 'DOCKER|mcr.microsoft.com/appsvc/staticsite:latest' +} +``` + +
    +

    + +### Example 5: _Web App_ This instance deploys the module as Web App with the set of logs configuration. @@ -652,7 +970,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -723,7 +1041,58 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 5: _WAF-aligned_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wslc001' +param serverFarmResourceId = '' +// Non-required parameters +param appInsightResourceId = '' +param appSettingsKeyValuePairs = { + ENABLE_ORYX_BUILD: 'True' + JAVA_OPTS: '' + SCM_DO_BUILD_DURING_DEPLOYMENT: 'True' +} +param location = '' +param logsConfiguration = { + applicationLogs: { + fileSystem: { + level: 'Verbose' + } + } + detailedErrorMessages: { + enabled: true + } + failedRequestsTracing: { + enabled: true + } + httpLogs: { + fileSystem: { + enabled: true + retentionInDays: 1 + retentionInMb: 35 + } + } +} +param managedIdentities = { + systemAssigned: true +} +param siteConfig = { + alwaysOn: true + appCommandLine: '' +} +``` + +
    +

    + +### Example 6: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -785,7 +1154,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -865,7 +1234,59 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 6: _Web App, using only defaults_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswaf001' +param serverFarmResourceId = '' +// Non-required parameters +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param httpsOnly = true +param location = '' +param publicNetworkAccess = 'Disabled' +param scmSiteAlsoStopped = true +param siteConfig = { + alwaysOn: true + healthCheckPath: '/healthz' + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] +} +param vnetContentShareEnabled = true +param vnetImagePullEnabled = true +param vnetRouteAllEnabled = true +``` + +
    +

    + +### Example 7: _Web App, using only defaults_ This instance deploys the module as Web App with the minimum set of required parameters. @@ -893,7 +1314,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -921,7 +1342,25 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 7: _Web App, using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 8: _Web App, using large parameter set_ This instance deploys the module as Web App with most of its features enabled. @@ -1138,7 +1577,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1389,7 +1828,214 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 8: _Web App, using only defaults_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswamax001' +param serverFarmResourceId = '' +// Non-required parameters +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param httpsOnly = true +param hybridConnectionRelays = [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + name: '0c2c82ef-069c-4085-b1bc-01614e0aa5ff' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scmSiteAlsoStopped = true +param siteConfig = { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] +} +param slots = [ + { + basicPublishingCredentialsPolicies: [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + hybridConnectionRelays: [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } + ] + name: 'slot1' + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'sites-slot1' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: '845ed19c-78e7-4422-aa3d-b78b67cd78a2' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + siteConfig: { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] + } + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } + { + basicPublishingCredentialsPolicies: [ + { + name: 'ftp' + } + { + name: 'scm' + } + ] + name: 'slot2' + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } +] +param storageAccountResourceId = '' +param storageAccountUseIdentityAuthentication = true +param vnetContentShareEnabled = true +param vnetImagePullEnabled = true +param vnetRouteAllEnabled = true +``` + +
    +

    + +### Example 9: _Web App, using only defaults_ This instance deploys the module as a Linux Web App with the minimum set of required parameters. @@ -1417,7 +2063,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1445,7 +2091,25 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 9: _Web App, using large parameter set_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,linux' +param name = 'wswalmin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +``` + +
    +

    + +### Example 10: _Web App, using large parameter set_ This instance deploys the module asa Linux Web App with most of its features enabled. @@ -1659,7 +2323,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -1907,7 +2571,211 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 10: _Web App_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,linux' +param name = 'wswalmax001' +param serverFarmResourceId = '' +// Non-required parameters +param basicPublishingCredentialsPolicies = [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } +] +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param httpsOnly = true +param hybridConnectionRelays = [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } +] +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param publicNetworkAccess = 'Disabled' +param roleAssignments = [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param scmSiteAlsoStopped = true +param siteConfig = { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] +} +param slots = [ + { + basicPublishingCredentialsPolicies: [ + { + allow: false + name: 'ftp' + } + { + allow: false + name: 'scm' + } + ] + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + hybridConnectionRelays: [ + { + resourceId: '' + sendKeyName: 'defaultSender' + } + ] + name: 'slot1' + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + service: 'sites-slot1' + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + siteConfig: { + alwaysOn: true + metadata: [ + { + name: 'CURRENT_STACK' + value: 'dotnetcore' + } + ] + } + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } + { + basicPublishingCredentialsPolicies: [ + { + name: 'ftp' + } + { + name: 'scm' + } + ] + name: 'slot2' + storageAccountResourceId: '' + storageAccountUseIdentityAuthentication: true + } +] +param storageAccountResourceId = '' +param storageAccountUseIdentityAuthentication = true +param vnetContentShareEnabled = true +param vnetImagePullEnabled = true +param vnetRouteAllEnabled = true +``` + +
    +

    + +### Example 11: _Web App_ This instance deploys the module as Web App with the set of api management configuration. @@ -1950,7 +2818,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2003,7 +2871,40 @@ module site 'br/public:avm/res/web/site:' = {

    -### Example 11: _Windows Web App for Containers, using only defaults_ +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app' +param name = 'wswc001' +param serverFarmResourceId = '' +// Non-required parameters +param apiManagementConfiguration = { + id: '' +} +param appInsightResourceId = '' +param appSettingsKeyValuePairs = { + ENABLE_ORYX_BUILD: 'True' + SCM_DO_BUILD_DURING_DEPLOYMENT: 'False' +} +param location = '' +param managedIdentities = { + systemAssigned: true +} +param siteConfig = { + alwaysOn: true + appCommandLine: '' +} +``` + +
    +

    + +### Example 12: _Windows Web App for Containers, using only defaults_ This instance deploys the module as a Windows based Container Web App with the minimum set of required parameters. @@ -2040,7 +2941,7 @@ module site 'br/public:avm/res/web/site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -2079,6 +2980,33 @@ module site 'br/public:avm/res/web/site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/site:' + +// Required parameters +param kind = 'app,container,windows' +param name = 'wswcamin001' +param serverFarmResourceId = '' +// Non-required parameters +param location = '' +param siteConfig = { + appSettings: [ + { + name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' + value: 'false' + } + ] + windowsFxVersion: 'DOCKER|mcr.microsoft.com/azure-app-service/windows/parkingpage:latest' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -2109,6 +3037,7 @@ module site 'br/public:avm/res/web/site:' = { | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`enabled`](#parameter-enabled) | bool | Setting this value to false disables the app (takes the app offline). | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`functionAppConfig`](#parameter-functionappconfig) | object | The Function App configuration object. | | [`hostNameSslStates`](#parameter-hostnamesslstates) | array | Hostname SSL states are used to manage the SSL bindings for app's hostnames. | | [`httpsOnly`](#parameter-httpsonly) | bool | Configures a site to accept only HTTPS requests. Issues redirect for HTTP requests. | | [`hybridConnectionRelays`](#parameter-hybridconnectionrelays) | array | Names of hybrid connection relays to connect app with. | @@ -2438,6 +3367,13 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` +### Parameter: `functionAppConfig` + +The Function App configuration object. + +- Required: No +- Type: object + ### Parameter: `hostNameSslStates` Hostname SSL states are used to manage the SSL bindings for app's hostnames. @@ -3001,6 +3937,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'App Compliance Automation Administrator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** diff --git a/avm/res/web/site/basic-publishing-credentials-policy/main.json b/avm/res/web/site/basic-publishing-credentials-policy/main.json index a2c95fcbcd..2f34f50dae 100644 --- a/avm/res/web/site/basic-publishing-credentials-policy/main.json +++ b/avm/res/web/site/basic-publishing-credentials-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5861139703409371797" + "version": "0.30.23.60470", + "templateHash": "2961784489694025029" }, "name": "Web Site Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Basic Publishing Credentials Policy.", diff --git a/avm/res/web/site/config--appsettings/README.md b/avm/res/web/site/config--appsettings/README.md index 17ff462236..db4a05b7d7 100644 --- a/avm/res/web/site/config--appsettings/README.md +++ b/avm/res/web/site/config--appsettings/README.md @@ -13,7 +13,7 @@ This module deploys a Site App Setting. | Resource Type | API Version | | :-- | :-- | -| `Microsoft.Web/sites/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | +| `Microsoft.Web/sites/config` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | ## Parameters @@ -35,6 +35,7 @@ This module deploys a Site App Setting. | :-- | :-- | :-- | | [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the app insight to leverage for this resource. | | [`appSettingsKeyValuePairs`](#parameter-appsettingskeyvaluepairs) | object | The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING. | +| [`currentAppSettings`](#parameter-currentappsettings) | object | The current app settings. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. | | [`storageAccountUseIdentityAuthentication`](#parameter-storageaccountuseidentityauthentication) | bool | If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'. | @@ -83,6 +84,14 @@ The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDas - Required: No - Type: object +### Parameter: `currentAppSettings` + +The current app settings. + +- Required: No +- Type: object +- Default: `{}` + ### Parameter: `storageAccountResourceId` Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. diff --git a/avm/res/web/site/config--appsettings/main.bicep b/avm/res/web/site/config--appsettings/main.bicep index 2f770a7774..202a2ac205 100644 --- a/avm/res/web/site/config--appsettings/main.bicep +++ b/avm/res/web/site/config--appsettings/main.bicep @@ -34,6 +34,9 @@ param appInsightResourceId string? @description('Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING.') param appSettingsKeyValuePairs object? +@description('Optional. The current app settings.') +param currentAppSettings object = {} + var azureWebJobsValues = !empty(storageAccountResourceId) && !(storageAccountUseIdentityAuthentication) ? { AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' @@ -51,9 +54,14 @@ var appInsightsValues = !empty(appInsightResourceId) } : {} -var expandedAppSettings = union(appSettingsKeyValuePairs ?? {}, azureWebJobsValues, appInsightsValues) +var expandedAppSettings = union( + currentAppSettings ?? {}, + appSettingsKeyValuePairs ?? {}, + azureWebJobsValues, + appInsightsValues +) -resource app 'Microsoft.Web/sites@2022-09-01' existing = { +resource app 'Microsoft.Web/sites@2023-12-01' existing = { name: appName } @@ -62,7 +70,7 @@ resource appInsight 'Microsoft.Insights/components@2020-02-02' existing = if (!e scope: resourceGroup(split(appInsightResourceId ?? '//', '/')[2], split(appInsightResourceId ?? '////', '/')[4]) } -resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = if (!empty(storageAccountResourceId)) { +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' existing = if (!empty(storageAccountResourceId)) { name: last(split(storageAccountResourceId ?? 'dummyName', '/')) scope: resourceGroup( split(storageAccountResourceId ?? '//', '/')[2], @@ -70,7 +78,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing ) } -resource appSettings 'Microsoft.Web/sites/config@2022-09-01' = { +resource appSettings 'Microsoft.Web/sites/config@2023-12-01' = { name: 'appsettings' kind: kind parent: app diff --git a/avm/res/web/site/config--appsettings/main.json b/avm/res/web/site/config--appsettings/main.json index c59a554e2a..0a244e922c 100644 --- a/avm/res/web/site/config--appsettings/main.json +++ b/avm/res/web/site/config--appsettings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8777070640548664577" + "version": "0.30.23.60470", + "templateHash": "10845600494881775271" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", @@ -66,13 +66,20 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { "app": { "existing": true, "type": "Microsoft.Web/sites", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[parameters('appName')]" }, "appInsight": { @@ -88,17 +95,17 @@ "condition": "[not(empty(parameters('storageAccountResourceId')))]", "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-01-01", + "apiVersion": "2023-05-01", "subscriptionId": "[split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2]]", "resourceGroup": "[split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]]", "name": "[last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))]" }, "appSettings": { "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "app", "appInsight", diff --git a/avm/res/web/site/config--authsettingsv2/main.json b/avm/res/web/site/config--authsettingsv2/main.json index 88d23811d2..40a2f7b4a3 100644 --- a/avm/res/web/site/config--authsettingsv2/main.json +++ b/avm/res/web/site/config--authsettingsv2/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15126303852151434516" + "version": "0.30.23.60470", + "templateHash": "9901606105705730734" }, "name": "Site Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", diff --git a/avm/res/web/site/config--logs/main.json b/avm/res/web/site/config--logs/main.json index a26a2fc11e..df3ade39ea 100644 --- a/avm/res/web/site/config--logs/main.json +++ b/avm/res/web/site/config--logs/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1719886395722436280" + "version": "0.30.23.60470", + "templateHash": "5314244939846396394" }, "name": "Site logs Config", "description": "This module deploys a Site logs Configuration.", diff --git a/avm/res/web/site/config--web/main.json b/avm/res/web/site/config--web/main.json index 3a995656e4..7e101b4952 100644 --- a/avm/res/web/site/config--web/main.json +++ b/avm/res/web/site/config--web/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7195763436259190781" + "version": "0.30.23.60470", + "templateHash": "4796843420829841335" }, "name": "Site Api Management Config", "description": "This module deploys a Site Api Management Configuration.", diff --git a/avm/res/web/site/extensions--msdeploy/main.json b/avm/res/web/site/extensions--msdeploy/main.json index fdc1b30f96..79be0b21b8 100644 --- a/avm/res/web/site/extensions--msdeploy/main.json +++ b/avm/res/web/site/extensions--msdeploy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", diff --git a/avm/res/web/site/hybrid-connection-namespace/relay/main.json b/avm/res/web/site/hybrid-connection-namespace/relay/main.json index c0dd469939..6f55127261 100644 --- a/avm/res/web/site/hybrid-connection-namespace/relay/main.json +++ b/avm/res/web/site/hybrid-connection-namespace/relay/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7661794789768148013" + "version": "0.30.23.60470", + "templateHash": "1833159536134902561" }, "name": "Web/Function Apps Hybrid Connection Relay", "description": "This module deploys a Site Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/main.bicep b/avm/res/web/site/main.bicep index b7418015b6..369399a325 100644 --- a/avm/res/web/site/main.bicep +++ b/avm/res/web/site/main.bicep @@ -69,6 +69,9 @@ param siteConfig object = { alwaysOn: true } +@description('Optional. The Function App configuration object.') +param functionAppConfig object? + @description('Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.') param storageAccountResourceId string? @@ -245,7 +248,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -resource app 'Microsoft.Web/sites@2022-09-01' = { +resource app 'Microsoft.Web/sites@2023-12-01' = { name: name location: location kind: kind @@ -265,6 +268,7 @@ resource app 'Microsoft.Web/sites@2022-09-01' = { keyVaultReferenceIdentity: keyVaultAccessIdentityResourceId virtualNetworkSubnetId: virtualNetworkSubnetId siteConfig: siteConfig + functionAppConfig: functionAppConfig clientCertEnabled: clientCertEnabled clientCertExclusionPaths: clientCertExclusionPaths clientCertMode: clientCertMode @@ -294,6 +298,7 @@ module app_appsettings 'config--appsettings/main.bicep' = if (!empty(appSettings storageAccountUseIdentityAuthentication: storageAccountUseIdentityAuthentication appInsightResourceId: appInsightResourceId appSettingsKeyValuePairs: appSettingsKeyValuePairs + currentAppSettings: !empty(app.id) ? list('${app.id}/config/appsettings', '2023-12-01').properties : {} } } @@ -351,6 +356,7 @@ module app_slots 'slot/main.bicep' = [ storageAccountRequired: slot.?storageAccountRequired ?? storageAccountRequired virtualNetworkSubnetId: slot.?virtualNetworkSubnetId ?? virtualNetworkSubnetId siteConfig: slot.?siteConfig ?? siteConfig + functionAppConfig: slot.?functionAppConfig ?? functionAppConfig storageAccountResourceId: slot.?storageAccountResourceId ?? storageAccountResourceId storageAccountUseIdentityAuthentication: slot.?storageAccountUseIdentityAuthentication ?? storageAccountUseIdentityAuthentication appInsightResourceId: slot.?appInsightResourceId ?? appInsightResourceId diff --git a/avm/res/web/site/main.json b/avm/res/web/site/main.json index e6eccb3688..ad24381ffc 100644 --- a/avm/res/web/site/main.json +++ b/avm/res/web/site/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7320044434284742277" + "version": "0.30.23.60470", + "templateHash": "12115053115954215642" }, "name": "Web/Function Apps", "description": "This module deploys a Web or Function App.", @@ -607,6 +607,13 @@ "description": "Optional. The site config object." } }, + "functionAppConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Function App configuration object." + } + }, "storageAccountResourceId": { "type": "string", "nullable": true, @@ -860,7 +867,7 @@ }, "app": { "type": "Microsoft.Web/sites", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -876,6 +883,7 @@ "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", "siteConfig": "[parameters('siteConfig')]", + "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", "clientCertMode": "[parameters('clientCertMode')]", @@ -998,7 +1006,8 @@ }, "appSettingsKeyValuePairs": { "value": "[parameters('appSettingsKeyValuePairs')]" - } + }, + "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites', parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites', parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1007,8 +1016,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8777070640548664577" + "version": "0.30.23.60470", + "templateHash": "10845600494881775271" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting.", @@ -1068,13 +1077,20 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { "app": { "existing": true, "type": "Microsoft.Web/sites", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[parameters('appName')]" }, "appInsight": { @@ -1090,17 +1106,17 @@ "condition": "[not(empty(parameters('storageAccountResourceId')))]", "existing": true, "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-01-01", + "apiVersion": "2023-05-01", "subscriptionId": "[split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2]]", "resourceGroup": "[split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]]", "name": "[last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))]" }, "appSettings": { "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "app", "appInsight", @@ -1164,8 +1180,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15126303852151434516" + "version": "0.30.23.60470", + "templateHash": "9901606105705730734" }, "name": "Site Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -1268,8 +1284,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1719886395722436280" + "version": "0.30.23.60470", + "templateHash": "5314244939846396394" }, "name": "Site logs Config", "description": "This module deploys a Site logs Configuration.", @@ -1363,8 +1379,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7195763436259190781" + "version": "0.30.23.60470", + "templateHash": "4796843420829841335" }, "name": "Site Api Management Config", "description": "This module deploys a Site Api Management Configuration.", @@ -1457,8 +1473,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", @@ -1581,6 +1597,9 @@ "siteConfig": { "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'siteConfig'), parameters('siteConfig'))]" }, + "functionAppConfig": { + "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'functionAppConfig'), parameters('functionAppConfig'))]" + }, "storageAccountResourceId": { "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'storageAccountResourceId'), parameters('storageAccountResourceId'))]" }, @@ -1676,8 +1695,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15729572124587777376" + "version": "0.30.23.60470", + "templateHash": "16398712095816733590" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -2250,6 +2269,13 @@ "description": "Optional. The site config object." } }, + "functionAppConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Function App config object." + } + }, "storageAccountResourceId": { "type": "string", "nullable": true, @@ -2496,7 +2522,7 @@ }, "slot": { "type": "Microsoft.Web/sites/slots", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), parameters('name'))]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -2511,6 +2537,7 @@ "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", "siteConfig": "[parameters('siteConfig')]", + "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", "clientCertMode": "[parameters('clientCertMode')]", @@ -2639,7 +2666,8 @@ }, "appSettingsKeyValuePairs": { "value": "[parameters('appSettingsKeyValuePairs')]" - } + }, + "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2648,8 +2676,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7111332561212908044" + "version": "0.30.23.60470", + "templateHash": "4751023237415156564" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -2715,6 +2743,13 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { @@ -2756,7 +2791,7 @@ "apiVersion": "2022-09-01", "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "appInsight", "app::slot", @@ -2824,8 +2859,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3412962465179136371" + "version": "0.30.23.60470", + "templateHash": "12145671704242923554" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -2946,8 +2981,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6875784212879192632" + "version": "0.30.23.60470", + "templateHash": "9837227282603977030" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", @@ -3072,8 +3107,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4120073340411344208" + "version": "0.30.23.60470", + "templateHash": "1330320751784094185" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", @@ -3178,8 +3213,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", @@ -4042,14 +4077,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('slot', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('slot', '2023-12-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('slot', '2022-09-01', 'full').location]" + "value": "[reference('slot', '2023-12-01', 'full').location]" }, "privateEndpoints": { "type": "array", @@ -4107,8 +4142,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5861139703409371797" + "version": "0.30.23.60470", + "templateHash": "2961784489694025029" }, "name": "Web Site Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Basic Publishing Credentials Policy.", @@ -4223,8 +4258,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7661794789768148013" + "version": "0.30.23.60470", + "templateHash": "1833159536134902561" }, "name": "Web/Function Apps Hybrid Connection Relay", "description": "This module deploys a Site Hybrid Connection Namespace Relay.", @@ -5111,7 +5146,7 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('app', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('app', '2023-12-01', 'full'), 'identity'), 'principalId'), '')]" }, "slotSystemAssignedMIPrincipalIds": { "type": "array", @@ -5128,7 +5163,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('app', '2022-09-01', 'full').location]" + "value": "[reference('app', '2023-12-01', 'full').location]" }, "defaultHostname": { "type": "string", diff --git a/avm/res/web/site/slot/README.md b/avm/res/web/site/slot/README.md index 063962c630..60d39f4ef0 100644 --- a/avm/res/web/site/slot/README.md +++ b/avm/res/web/site/slot/README.md @@ -21,7 +21,7 @@ This module deploys a Web or Function App Deployment Slot. | `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | | `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | | `Microsoft.Web/sites/extensions` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/extensions) | -| `Microsoft.Web/sites/slots` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots) | +| `Microsoft.Web/sites/slots` | [2023-12-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites/slots) | | `Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/config` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/sites) | | `Microsoft.Web/sites/slots/hybridConnectionNamespaces/relays` | [2022-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Web/2022-09-01/sites/slots/hybridConnectionNamespaces/relays) | @@ -61,6 +61,7 @@ This module deploys a Web or Function App Deployment Slot. | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`enabled`](#parameter-enabled) | bool | Setting this value to false disables the app (takes the app offline). | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`functionAppConfig`](#parameter-functionappconfig) | object | The Function App config object. | | [`hostNameSslStates`](#parameter-hostnamesslstates) | array | Hostname SSL states are used to manage the SSL bindings for app's hostnames. | | [`httpsOnly`](#parameter-httpsonly) | bool | Configures a slot to accept only HTTPS requests. Issues redirect for HTTP requests. | | [`hybridConnectionRelays`](#parameter-hybridconnectionrelays) | array | Names of hybrid connection relays to connect app with. | @@ -387,6 +388,13 @@ Enable/Disable usage telemetry for module. - Type: bool - Default: `True` +### Parameter: `functionAppConfig` + +The Function App config object. + +- Required: No +- Type: object + ### Parameter: `hostNameSslStates` Hostname SSL states are used to manage the SSL bindings for app's hostnames. @@ -793,6 +801,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -936,6 +955,15 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'App Compliance Automation Administrator'` + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** diff --git a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json index 93bbb33ac2..f5534dba2f 100644 --- a/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json +++ b/avm/res/web/site/slot/basic-publishing-credentials-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6875784212879192632" + "version": "0.30.23.60470", + "templateHash": "9837227282603977030" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", diff --git a/avm/res/web/site/slot/config--appsettings/README.md b/avm/res/web/site/slot/config--appsettings/README.md index 6be3108fe1..a4eaf7b5e3 100644 --- a/avm/res/web/site/slot/config--appsettings/README.md +++ b/avm/res/web/site/slot/config--appsettings/README.md @@ -36,6 +36,7 @@ This module deploys a Site Slot App Setting. | :-- | :-- | :-- | | [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the app insight to leverage for this resource. | | [`appSettingsKeyValuePairs`](#parameter-appsettingskeyvaluepairs) | object | The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING. | +| [`currentAppSettings`](#parameter-currentappsettings) | object | The current app settings. | | [`storageAccountResourceId`](#parameter-storageaccountresourceid) | string | Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. | | [`storageAccountUseIdentityAuthentication`](#parameter-storageaccountuseidentityauthentication) | bool | If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'. | @@ -91,6 +92,14 @@ The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDas - Required: No - Type: object +### Parameter: `currentAppSettings` + +The current app settings. + +- Required: No +- Type: object +- Default: `{}` + ### Parameter: `storageAccountResourceId` Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions. diff --git a/avm/res/web/site/slot/config--appsettings/main.bicep b/avm/res/web/site/slot/config--appsettings/main.bicep index 74095161a8..2fbe7b81d4 100644 --- a/avm/res/web/site/slot/config--appsettings/main.bicep +++ b/avm/res/web/site/slot/config--appsettings/main.bicep @@ -37,6 +37,9 @@ param appInsightResourceId string? @description('Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING.') param appSettingsKeyValuePairs object? +@description('Optional. The current app settings.') +param currentAppSettings object = {} + var azureWebJobsValues = !empty(storageAccountResourceId) && !(storageAccountUseIdentityAuthentication) ? { AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' @@ -54,7 +57,12 @@ var appInsightsValues = !empty(appInsightResourceId) } : {} -var expandedAppSettings = union(appSettingsKeyValuePairs ?? {}, azureWebJobsValues, appInsightsValues) +var expandedAppSettings = union( + currentAppSettings ?? {}, + appSettingsKeyValuePairs ?? {}, + azureWebJobsValues, + appInsightsValues +) resource app 'Microsoft.Web/sites@2022-09-01' existing = { name: appName diff --git a/avm/res/web/site/slot/config--appsettings/main.json b/avm/res/web/site/slot/config--appsettings/main.json index 48ed22304b..db3ee7ad32 100644 --- a/avm/res/web/site/slot/config--appsettings/main.json +++ b/avm/res/web/site/slot/config--appsettings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7111332561212908044" + "version": "0.30.23.60470", + "templateHash": "4751023237415156564" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -72,6 +72,13 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { @@ -113,7 +120,7 @@ "apiVersion": "2022-09-01", "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "appInsight", "app::slot", diff --git a/avm/res/web/site/slot/config--authsettingsv2/main.json b/avm/res/web/site/slot/config--authsettingsv2/main.json index 489aa559b3..65b5d4fa2b 100644 --- a/avm/res/web/site/slot/config--authsettingsv2/main.json +++ b/avm/res/web/site/slot/config--authsettingsv2/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3412962465179136371" + "version": "0.30.23.60470", + "templateHash": "12145671704242923554" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", diff --git a/avm/res/web/site/slot/extensions--msdeploy/main.json b/avm/res/web/site/slot/extensions--msdeploy/main.json index fdc1b30f96..79be0b21b8 100644 --- a/avm/res/web/site/slot/extensions--msdeploy/main.json +++ b/avm/res/web/site/slot/extensions--msdeploy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", diff --git a/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json b/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json index fb8ad95a8d..8fd1b8a2bb 100644 --- a/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json +++ b/avm/res/web/site/slot/hybrid-connection-namespace/relay/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4120073340411344208" + "version": "0.30.23.60470", + "templateHash": "1330320751784094185" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", diff --git a/avm/res/web/site/slot/main.bicep b/avm/res/web/site/slot/main.bicep index b871bf0960..266ea3d893 100644 --- a/avm/res/web/site/slot/main.bicep +++ b/avm/res/web/site/slot/main.bicep @@ -57,6 +57,9 @@ param siteConfig object = { alwaysOn: true } +@description('Optional. The Function App config object.') +param functionAppConfig object? + @description('Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.') param storageAccountResourceId string? @@ -216,7 +219,7 @@ resource app 'Microsoft.Web/sites@2021-03-01' existing = { name: appName } -resource slot 'Microsoft.Web/sites/slots@2022-09-01' = { +resource slot 'Microsoft.Web/sites/slots@2023-12-01' = { name: name parent: app location: location @@ -236,6 +239,7 @@ resource slot 'Microsoft.Web/sites/slots@2022-09-01' = { keyVaultReferenceIdentity: keyVaultAccessIdentityResourceId virtualNetworkSubnetId: virtualNetworkSubnetId siteConfig: siteConfig + functionAppConfig: functionAppConfig clientCertEnabled: clientCertEnabled clientCertExclusionPaths: clientCertExclusionPaths clientCertMode: clientCertMode @@ -264,6 +268,7 @@ module slot_appsettings 'config--appsettings/main.bicep' = if (!empty(appSetting storageAccountUseIdentityAuthentication: storageAccountUseIdentityAuthentication appInsightResourceId: appInsightResourceId appSettingsKeyValuePairs: appSettingsKeyValuePairs + currentAppSettings: !empty(slot.id) ? list('${slot.id}/config/appsettings', '2023-12-01').properties : {} } } diff --git a/avm/res/web/site/slot/main.json b/avm/res/web/site/slot/main.json index 8f8f81e34a..ede1b02e37 100644 --- a/avm/res/web/site/slot/main.json +++ b/avm/res/web/site/slot/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "15729572124587777376" + "version": "0.30.23.60470", + "templateHash": "16398712095816733590" }, "name": "Web/Function App Deployment Slots", "description": "This module deploys a Web or Function App Deployment Slot.", @@ -579,6 +579,13 @@ "description": "Optional. The site config object." } }, + "functionAppConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The Function App config object." + } + }, "storageAccountResourceId": { "type": "string", "nullable": true, @@ -825,7 +832,7 @@ }, "slot": { "type": "Microsoft.Web/sites/slots", - "apiVersion": "2022-09-01", + "apiVersion": "2023-12-01", "name": "[format('{0}/{1}', parameters('appName'), parameters('name'))]", "location": "[parameters('location')]", "kind": "[parameters('kind')]", @@ -840,6 +847,7 @@ "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", "siteConfig": "[parameters('siteConfig')]", + "functionAppConfig": "[parameters('functionAppConfig')]", "clientCertEnabled": "[parameters('clientCertEnabled')]", "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", "clientCertMode": "[parameters('clientCertMode')]", @@ -968,7 +976,8 @@ }, "appSettingsKeyValuePairs": { "value": "[parameters('appSettingsKeyValuePairs')]" - } + }, + "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -977,8 +986,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "7111332561212908044" + "version": "0.30.23.60470", + "templateHash": "4751023237415156564" }, "name": "Site Slot App Settings", "description": "This module deploys a Site Slot App Setting.", @@ -1044,6 +1053,13 @@ "metadata": { "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." } + }, + "currentAppSettings": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The current app settings." + } } }, "resources": { @@ -1085,7 +1101,7 @@ "apiVersion": "2022-09-01", "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", + "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(parameters('storageAccountResourceId'), '//'), '/')[2], split(coalesce(parameters('storageAccountResourceId'), '////'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), '2023-01-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(coalesce(parameters('storageAccountResourceId'), 'dummyName'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", "dependsOn": [ "appInsight", "app::slot", @@ -1153,8 +1169,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "3412962465179136371" + "version": "0.30.23.60470", + "templateHash": "12145671704242923554" }, "name": "Site Slot Auth Settings V2 Config", "description": "This module deploys a Site Auth Settings V2 Configuration.", @@ -1275,8 +1291,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "6875784212879192632" + "version": "0.30.23.60470", + "templateHash": "9837227282603977030" }, "name": "Web Site Slot Basic Publishing Credentials Policies", "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy.", @@ -1401,8 +1417,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "4120073340411344208" + "version": "0.30.23.60470", + "templateHash": "1330320751784094185" }, "name": "Web/Function Apps Slot Hybrid Connection Relay", "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay.", @@ -1507,8 +1523,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "2006653133597094766" + "version": "0.30.23.60470", + "templateHash": "8769701913978391000" }, "name": "Site Deployment Extension ", "description": "This module deploys a Site extension for MSDeploy.", @@ -2371,14 +2387,14 @@ "metadata": { "description": "The principal ID of the system assigned identity." }, - "value": "[coalesce(tryGet(tryGet(reference('slot', '2022-09-01', 'full'), 'identity'), 'principalId'), '')]" + "value": "[coalesce(tryGet(tryGet(reference('slot', '2023-12-01', 'full'), 'identity'), 'principalId'), '')]" }, "location": { "type": "string", "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('slot', '2022-09-01', 'full').location]" + "value": "[reference('slot', '2023-12-01', 'full').location]" }, "privateEndpoints": { "type": "array", diff --git a/avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep b/avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep new file mode 100644 index 0000000000..dd34e10b1c --- /dev/null +++ b/avm/res/web/site/tests/e2e/functionApp.settings/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Server Farm to create.') +param serverFarmName string + +resource serverFarm 'Microsoft.Web/serverfarms@2022-03-01' = { + name: serverFarmName + location: location + sku: { + name: 'S1' + tier: 'Standard' + size: 'S1' + family: 'S' + capacity: 1 + } + properties: {} +} + +@description('The resource ID of the created Server Farm.') +output serverFarmResourceId string = serverFarm.id diff --git a/avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep b/avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep new file mode 100644 index 0000000000..a62f7217a1 --- /dev/null +++ b/avm/res/web/site/tests/e2e/functionApp.settings/main.test.bicep @@ -0,0 +1,67 @@ +targetScope = 'subscription' + +metadata name = 'Function App, using only defaults' +metadata description = 'This instance deploys the module as Function App with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-web.sites-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'wsfaset' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + serverFarmName: 'dep-${namePrefix}-sf-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + kind: 'functionapp' + serverFarmResourceId: nestedDependencies.outputs.serverFarmResourceId + appSettingsKeyValuePairs: { + AzureFunctionsJobHost__logging__logLevel__default: 'Trace' + FUNCTIONS_EXTENSION_VERSION: '~4' + FUNCTIONS_WORKER_RUNTIME: 'dotnet' + } + } + dependsOn: [ + nestedDependencies + ] + } +] diff --git a/avm/res/web/site/version.json b/avm/res/web/site/version.json index 0f81d22abc..bb03e3a03d 100644 --- a/avm/res/web/site/version.json +++ b/avm/res/web/site/version.json @@ -1,7 +1,7 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.8", + "version": "0.10", "pathFilters": [ "./main.json" ] -} \ No newline at end of file +} diff --git a/avm/res/web/static-site/README.md b/avm/res/web/static-site/README.md index c0b10e3875..fda575fffb 100644 --- a/avm/res/web/static-site/README.md +++ b/avm/res/web/static-site/README.md @@ -62,7 +62,7 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -84,6 +84,22 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/static-site:' + +// Required parameters +param name = 'wssmin001' +// Non-required parameters +param location = '' +``` + +
    +

    + ### Example 2: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -186,7 +202,7 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -308,6 +324,98 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/static-site:' + +// Required parameters +param name = 'wssmax001' +// Non-required parameters +param allowConfigFileUpdates = true +param appSettings = { + foo: 'bar' + setting: 1 +} +param enterpriseGradeCdnStatus = 'Disabled' +param functionAppSettings = { + foo: 'bar' + setting: 1 +} +param linkedBackend = { + resourceId: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param managedIdentities = { + systemAssigned: true + userAssignedResourceIds: [ + '' + ] +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + } +] +param roleAssignments = [ + { + name: 'ba1328f0-c7ab-47bf-afbf-0637b9c02bbe' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param sku = 'Standard' +param stagingEnvironmentPolicy = 'Enabled' +param tags = { + 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. @@ -375,7 +483,7 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

    -via JSON Parameter file +via JSON parameters file ```json { @@ -458,6 +566,63 @@ module staticSite 'br/public:avm/res/web/static-site:' = {

    +

    + +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/web/static-site:' + +// Required parameters +param name = 'wsswaf001' +// Non-required parameters +param allowConfigFileUpdates = true +param appSettings = { + foo: 'bar' + setting: 1 +} +param enterpriseGradeCdnStatus = 'Disabled' +param functionAppSettings = { + foo: 'bar' + setting: 1 +} +param linkedBackend = { + resourceId: '' +} +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param sku = 'Standard' +param stagingEnvironmentPolicy = 'Enabled' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +``` + +
    +

    + ## Parameters **Required parameters** @@ -940,6 +1105,17 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'DNS Resolver Contributor'` + - `'DNS Zone Contributor'` + - `'Domain Services Contributor'` + - `'Domain Services Reader'` + - `'Network Contributor'` + - `'Owner'` + - `'Private DNS Zone Contributor'` + - `'Reader'` + - `'Role Based Access Control Administrator (Preview)'` **Required parameters** @@ -1073,6 +1249,14 @@ Array of role assignments to create. - Required: No - Type: array +- Roles configurable by name: + - `'Contributor'` + - `'Owner'` + - `'Reader'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + - `'Web Plan Contributor'` + - `'Website Contributor'` **Required parameters** diff --git a/avm/utilities/e2e-template-assets/scripts/Wait-ForImageBuild.ps1 b/avm/utilities/e2e-template-assets/scripts/Wait-ForImageBuild.ps1 new file mode 100644 index 0000000000..bce2306a21 --- /dev/null +++ b/avm/utilities/e2e-template-assets/scripts/Wait-ForImageBuild.ps1 @@ -0,0 +1,97 @@ +<# +.SYNOPSIS +Fetch the latest build status for the provided image template + +.DESCRIPTION +Fetch the latest build status for the provided image template + +.PARAMETER ResourceGroupName +Required. The name of the Resource Group containing the image template + +.PARAMETER ImageTemplateName +Required. The name of the image template to query to build status for. E.g. 'lin_it-2022-02-20-16-17-38' + +.EXAMPLE +. 'Wait-ForImageBuild.ps1' -ResourceGroupName' 'myRG' -ImageTemplateName 'lin_it-2022-02-20-16-17-38' + +Check the current build status of Image Template 'lin_it-2022-02-20-16-17-38' in Resource Group 'myRG' +#> +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string] $ResourceGroupName, + + [Parameter(Mandatory)] + [string] $ImageTemplateName +) + +begin { + Write-Debug ('[{0} entered]' -f $MyInvocation.MyCommand) +} + +process { + # Logic + # ----- + $context = Get-AzContext + $subscriptionId = $context.Subscription.Id + $currentRetry = 1 + $maximumRetries = 720 + $timeToWait = 15 + $maxTimeCalc = '{0:hh\:mm\:ss}' -f [timespan]::fromseconds($maximumRetries * $timeToWait) + do { + + # Runnning fetch in retry as it happened that the status was not available + $statusFetchRetryCount = 3 + $statusFetchCurrentRetry = 1 + do { + $path = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.VirtualMachineImages/imageTemplates/{2}?api-version=2020-02-14' -f $subscriptionId, $ResourceGroupName, $ImageTemplateName + $requestInputObject = @{ + Method = 'GET' + Path = $path + } + + $response = ((Invoke-AzRestMethod @requestInputObject).Content | ConvertFrom-Json).properties + + if ($response.lastRunStatus) { + $latestStatus = $response.lastRunStatus + break + } + Start-Sleep 5 + $statusFetchCurrentRetry++ + } while ($statusFetchCurrentRetry -le $statusFetchRetryCount) + + if (-not $latestStatus) { + Write-Verbose ('Image Build failed with error: [{0}]' -f $response.provisioningError.message) -Verbose + $latestStatus = 'failed' + } + + + if ($latestStatus -eq 'failed' -or $latestStatus.runState.ToLower() -eq 'failed') { + $failedMessage = 'Image Template [{0}] build failed with status [{1}]. API reply: [{2}]' -f $ImageTemplateName, $latestStatus.runState, $response.lastRunStatus.message + Write-Verbose $failedMessage -Verbose + throw $failedMessage + } + + if ($latestStatus.runState.ToLower() -notIn @('running', 'new')) { + break + } + + $currTimeCalc = '{0:hh\:mm\:ss}' -f [timespan]::fromseconds($currentRetry * $timeToWait) + + Write-Verbose ('[{0}] Waiting 15 seconds [{1}|{2}]' -f (Get-Date -Format 'HH:mm:ss'), $currTimeCalc, $maxTimeCalc) -Verbose + $currentRetry++ + Start-Sleep $timeToWait + } while ($currentRetry -le $maximumRetries) + + if ($latestStatus) { + $duration = New-TimeSpan -Start $latestStatus.startTime -End $latestStatus.endTime + Write-Verbose ('It took [{0}] minutes and [{1}] seconds to build and distribute the image.' -f $duration.Minutes, $duration.Seconds) -Verbose + } else { + Write-Warning "Timeout at [$currTimeCalc]. Note, the Azure Image Builder may still succeed." + } + return $latestStatus +} + +end { + Write-Debug ('[{0} existed]' -f $MyInvocation.MyCommand) +} diff --git a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Invoke-ResourceRemoval.ps1 b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Invoke-ResourceRemoval.ps1 index b2723eaaf1..455ba34ee0 100644 --- a/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Invoke-ResourceRemoval.ps1 +++ b/avm/utilities/pipelines/e2eValidation/resourceRemoval/helper/Invoke-ResourceRemoval.ps1 @@ -147,6 +147,64 @@ function Invoke-ResourceRemoval { } break } + 'Microsoft.VirtualMachineImages/imageTemplates' { + # Note: If you ever run into the issue that you cannot remove the image template because of an issue with the MSI (e.g., because the below logic was not executed in the pipeline), you can follow these manual steps: + # 1. Unassign the existing MSI (az image builder identity remove --resource-group --name --user-assigned --yes) + # 2. Trigger image template removal (will fail, but remove the cached 'running' state) + # 3. Assign a new MSI (az image builder identity assign --resource-group --name --user-assigned ) + # 4. Trigger image template removal again, which removes the resource for good + + $resourceGroupName = $ResourceId.Split('/')[4] + $resourceName = Split-Path $ResourceId -Leaf + + # Remove resource + if ($PSCmdlet.ShouldProcess("Image Template [$resourceName]", 'Remove')) { + + $removeRequestInputObject = @{ + Method = 'DELETE' + Path = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.VirtualMachineImages/imageTemplates/{2}?api-version=2022-07-01' -f $subscriptionId, $resourceGroupName, $resourceName + } + $removalResponse = Invoke-AzRestMethod @removeRequestInputObject + if ($removalResponse.StatusCode -notlike '2*') { + $responseContent = $removalResponse.Content | ConvertFrom-Json + throw ('{0} : {1}' -f $responseContent.error.code, $responseContent.error.message) + } + + # Wait for template to be removed. If we don't wait, it can happen that its MSI is removed too soon, locking the resource from deletion + $retryCount = 1 + $retryLimit = 240 + $retryInterval = 15 + do { + $getRequestInputObject = @{ + Method = 'GET' + Path = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.VirtualMachineImages/imageTemplates/{2}?api-version=2022-07-01' -f $subscriptionId, $resourceGroupName, $resourceName + } + $getReponse = Invoke-AzRestMethod @getRequestInputObject + + if ($getReponse.StatusCode -eq 400) { + # Invalid request + throw ($imageTgetReponseemplate.Content | ConvertFrom-Json).error.message + } elseif ($getReponse.StatusCode -eq 404) { + # Resource not found, removal was successful + $templateExists = $false + } elseif ($getReponse.StatusCode -eq '200') { + # Resource still around - try again + $templateExists = $true + Write-Verbose (' [⏱️] Waiting {0} seconds for Image Template to be removed. [{1}/{2}]' -f $retryInterval, $retryCount, $retryLimit) -Verbose + Start-Sleep -Seconds $retryInterval + $retryCount++ + } else { + throw ('Failed request. Response: [{0}]' -f ($getReponse | Out-String)) + } + } while ($templateExists -and $retryCount -lt $retryLimit) + + if ($retryCount -ge $retryLimit) { + Write-Warning (' [!] Image Template [{0}] was not removed after {1} seconds. Continuing with resource removal.' -f $resourceName, ($retryCount * $retryInterval)) + break + } + } + break + } 'Microsoft.MachineLearningServices/workspaces' { $subscriptionId = $ResourceId.Split('/')[2] $resourceGroupName = $ResourceId.Split('/')[4] diff --git a/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 b/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 index 1f5e5389f2..df38f9eb2f 100644 --- a/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Get-NestedResourceList.ps1 @@ -29,13 +29,20 @@ function Get-NestedResourceList { if ($TemplateFileContent.resources -is [System.Collections.Hashtable]) { # With the introduction of user defined types, a compiled template's resources are not part of an ordered hashtable instead of an array. $currLevelResources += $TemplateFileContent.resources.Keys | ForEach-Object { - $TemplateFileContent.resources[$_] + $elem = $TemplateFileContent.resources[$_] + $elem['identifier'] = $_ + $elem } | Where-Object { $_.existing -ne $true } } else { # Default array - $currLevelResources += $TemplateFileContent.resources + $currLevelResources += $TemplateFileContent.resources | ForEach-Object { + $_['identifier'] = $_.name + $_ + } | Where-Object { + $_.existing -ne $true + } } } foreach ($resource in $currLevelResources) { diff --git a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 index 3669c1f75a..2562eb4eb9 100644 --- a/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 +++ b/avm/utilities/pipelines/sharedScripts/Set-ModuleReadMe.ps1 @@ -390,7 +390,7 @@ function Set-DefinitionSection { ) } } else { - $formattedDefaultValue = $null + $formattedDefaultValue = $null # Reset value for future iterations } # Format allowed values @@ -420,7 +420,31 @@ function Set-DefinitionSection { ) } } else { - $formattedAllowedValues = $null + $formattedAllowedValues = $null # Reset value for future iterations + } + + # Special case for 'roleAssignments' parameter + if (($parameter.name -eq 'roleAssignments') -and ($TemplateFileContent.variables.keys -contains 'builtInRoleNames')) { + if ([String]::IsNullOrEmpty($ParentName)) { + # Top-level invocation + $roles = $TemplateFileContent.variables.builtInRoleNames.Keys + } else { + # Nested-invocation (requires e.g., roles for of nested private endpoint template) + $flattendResources = Get-NestedResourceList -TemplateFileContent $TemplateFileContent + if ($resourceIdentifier = $flattendResources.identifier | Where-Object { $_ -match "^.*_$ParentName`$" }) { + $roles = ($flattendResources | Where-Object { + $_.identifier -eq $resourceIdentifier + }).properties.template.variables.builtInRoleNames.Keys + } else { + Write-Warning ('Failed to identify roles for parameter [{0}] of type [{1}] as resource with identifier [{2}] was not found in the corresponding linked template.' -f $parameter.name, $ParentName, "*_$ParentName") + } + } + $formattedRoleNames = $roles.count -gt 0 ? @( + '- Roles configurable by name:', + ($roles | ForEach-Object { " - ``'$_'``" } | Out-String).TrimEnd() + ) : $null + } else { + $formattedRoleNames = $null # Reset value for future iterations } # Format example @@ -457,7 +481,8 @@ function Set-DefinitionSection { ('- Type: {0}' -f $type), ((-not [String]::IsNullOrEmpty($formattedDefaultValue)) ? $formattedDefaultValue : $null), ((-not [String]::IsNullOrEmpty($formattedAllowedValues)) ? $formattedAllowedValues : $null), - ((-not [String]::IsNullOrEmpty($formattedExample)) ? $formattedExample : $null) + ((-not [String]::IsNullOrEmpty($formattedRoleNames)) ? $formattedRoleNames : $null), + ((-not [String]::IsNullOrEmpty($formattedExample)) ? $formattedExample : $null), '' ) | Where-Object { $null -ne $_ } @@ -1392,6 +1417,9 @@ function Set-UsageExamplesSection { [Parameter(Mandatory = $false)] [bool] $addBicep = $true, + [Parameter(Mandatory = $false)] + [bool] $addBicepParametersFile = $true, + [Parameter(Mandatory = $false)] [string] $SectionStartIdentifier = '## Usage examples' ) @@ -1566,20 +1594,32 @@ function Set-UsageExamplesSection { } } - # [5/6] Convert Bicep parameter block to JSON parameter block to enable processing + # [4/6] Convert Bicep parameter block to JSON parameter block to enable processing $conversionInputObject = @{ BicepParamBlock = ($paramsBlockArray | Out-String).TrimEnd() CurrentFilePath = $testFilePath } $paramsInJSONFormat = ConvertTo-FormattedJSONParameterObject @conversionInputObject - # [6/6] Convert JSON parameters back to Bicep and order & format them + # [5/6] Convert JSON parameters back to Bicep and order & format them $conversionInputObject = @{ JSONParameters = $paramsInJSONFormat RequiredParametersList = $RequiredParametersList } $bicepExample = ConvertTo-FormattedBicep @conversionInputObject + # [6/6] Convert the Bicep format to a Bicep parameters file format + if ($bicepExample.length -gt 0) { + $bicepParamBlockArray = $bicepExample -split '\r?\n' + $topLevelParamIndent = ([regex]::Match($bicepParamBlockArray[0], '^(\s+).*')).Captures.Groups[1].Value.Length + $bicepParametersFileExample = $bicepParamBlockArray | ForEach-Object { + $line = $_ + $line = $line -replace "^(\s{$topLevelParamIndent})([a-zA-Z]*)(:)(.*)", 'param $2 =$4' # Update any [ xyz: abc] to [param xyz = abc] + $line = $line -replace "^\s{$topLevelParamIndent}", '' # Update any [ xyz: abc] to [xyz: abc] + $line + } + } + # --------------------- # # Add Bicep example # # --------------------- # @@ -1627,7 +1667,7 @@ function Set-UsageExamplesSection { '', '

    ' '' - 'via JSON Parameter file' + 'via JSON parameters file' '' '```json', $orderedJSONExample.Trim() @@ -1637,6 +1677,33 @@ function Set-UsageExamplesSection { '

    ' ) } + + # ---------------------------------------- # + # Add Bicep parameters file example # + # ---------------------------------------- # + if ($addBicepParametersFile) { + + $formattedbicepParametersFileExample = @( + "using 'br/public:$($brLink):$($targetVersion)'" + '' + ) + $bicepParametersFileExample + + + # Build result + $testFilesContent += @( + '', + '

    ' + '' + 'via Bicep parameters file' + '' + '```bicep-params', + ($formattedbicepParametersFileExample | ForEach-Object { "$_" }).TrimEnd(), + '```', + '', + '
    ', + '

    ' + ) + } } else { # Non-module deployment (e.g., utility deployment) diff --git a/avm/utilities/tools/Invoke-WorkflowsFailedJobsReRun.ps1 b/avm/utilities/tools/Invoke-WorkflowsFailedJobsReRun.ps1 new file mode 100644 index 0000000000..adf77897e3 --- /dev/null +++ b/avm/utilities/tools/Invoke-WorkflowsFailedJobsReRun.ps1 @@ -0,0 +1,415 @@ +#region helper functions +<# +.SYNOPSIS +Get a list of all GitHub module workflows + +.DESCRIPTION +Get a list of all GitHub module workflows. Does not return all properties but only the relevant ones. + +.PARAMETER PersonalAccessToken +Optional. The PAT to use to interact with either GitHub / Azure DevOps. If not provided, the script will use the GitHub CLI to authenticate. + +.PARAMETER RepositoryOwner +Mandatory. The repository's organization. + +.PARAMETER RepositoryName +Mandatory. The name of the repository to fetch the workflows from. + +.PARAMETER IncludeDisabled +Optional. Set if you want to also include disabled workflows in the result. + +.PARAMETER Filter +Optional. A regex filter to apply when fetching the workflows. By default we fetch all module workflows. + +.EXAMPLE +Get-GitHubModuleWorkflowList -PersonalAccessToken '' -RepositoryOwner 'Azure' -RepositoryName 'bicep-registry-modules' + +Get all module workflows from repository 'Azure/bicep-registry-modules' +#> +function Get-GitHubModuleWorkflowList { + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [string] $PersonalAccessToken, + + [Parameter(Mandatory = $true)] + [string] $RepositoryOwner, + + [Parameter(Mandatory = $true)] + [string] $RepositoryName, + + [Parameter(Mandatory = $false)] + [switch] $IncludeDisabled, + + [Parameter(Mandatory = $false)] + [string] $Filter = 'avm\.(?:res|ptn|utl)' + ) + + $allWorkflows = @() + + $page = 1 + do { + $queryUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/workflows?per_page=100&page=$page" + if ($PersonalAccessToken) { + # Using PAT + $requestInputObject = @{ + Method = 'GET' + Uri = "https://api.github.com$queryUrl" + Headers = @{ + Authorization = "Bearer $PersonalAccessToken" + } + } + $response = Invoke-RestMethod @requestInputObject + } else { + # Using GH API instead of 'gh workflow list' to get all results instead of just the first few + $requestInputObject = @( + '-H', 'Accept: application/vnd.github+json', + '-H', 'X-GitHub-Api-Version: 2022-11-28', + $queryUrl + ) + $response = (gh api @requestInputObject | ConvertFrom-Json) + } + + if (-not $response.workflows) { + Write-Error "Request failed. Reponse: [$response]" + } + + $allWorkflows += $response.workflows | Select-Object -Property @('id', 'name', 'path', 'badge_url', 'state') | Where-Object { + $_.name -match $Filter -and + ($IncludeDisabled ? $true : $_.state -eq 'active') + } + + $expectedPages = [math]::ceiling($response.total_count / 100) + $page++ + } while ($page -le $expectedPages) + + return $allWorkflows +} + + +<# +.SYNOPSIS +Invoke the re-run for a given set of workflow runs. + +.DESCRIPTION +Invoke the re-run for a given set of workflow runs. + +.PARAMETER RestInputObject +Mandatory. The REST parameters to use for the re-run. Must contain the 'RepositoryOwner' and 'RepositoryName' keys and may contain the 'PersonalAccessToken' key. + +.PARAMETER RunsToReTrigger +Manadatory. The workflow runs to re-trigger. + +.PARAMETER TotalNumberOfWorkflows +Mandatory. The total number of workflows to re-trigger. + +.EXAMPLE +Invoke-ReRun -RestInputObject @{ RepositoryOwner = 'Azure'; RepositoryName = 'bicep-registry-modules' } -RunsToReTrigger @(@{ id = 123; name = 'keyvaultworkflow'}) -TotalNumberOfWorkflows 123 + +Re-run the failed jobs for all provided runs in the repository [Azure/bicep-registry-modules]. +#> +function Invoke-ReRun { + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory)] + [hashtable] $RestInputObject, + + [Parameter(Mandatory)] + [object[]] $RunsToReTrigger, + + [Parameter(Mandatory)] + [int] $TotalNumberOfWorkflows + ) + + $totalCount = $RunsToReTrigger.Count + $currentCount = 1 + Write-Verbose ('Runs to re-run failed jobs for [{0}/{1}]' -f $RunsToReTrigger.Count, $TotalNumberOfWorkflows) -Verbose + foreach ($run in $RunsToReTrigger) { + $percentageComplete = [math]::Round(($currentCount / $totalCount) * 100) + Write-Progress -Activity ('Re-running failed jobs for workflow [{0}]' -f $run.name) -Status "$percentageComplete% complete" -PercentComplete $percentageComplete + + if ($PSCmdlet.ShouldProcess(("Re-run of failed jobs for GitHub workflow [{0}] for branch [$TargetBranch]" -f $run.name), 'Invoke')) { + $null = Invoke-GitHubWorkflowRunFailedJobsReRun @RestInputObject -RunId $run.id + } + $currentCount++ + } +} + +<# +.SYNOPSIS +Get the latest run of a GitHub workflow for a given branch. + +.DESCRIPTION +Get the latest run of a GitHub workflow for a given branch. + +.PARAMETER PersonalAccessToken +Optional. The PAT to use to interact with either GitHub. If not provided, the script will use the GitHub CLI to authenticate. + +.PARAMETER RepositoryOwner +Optional. The GitHub organization the workfows are located in. + +.PARAMETER RepositoryName +Optional. The GitHub repository the workfows are located in. + +.PARAMETER WorkflowId +Required. The ID of the workflow to get the latest run for. + +.PARAMETER TargetBranch +Optional. The branch to get the latest run for. Defaults to 'main'. + +.EXAMPLE +Get-GitHubModuleWorkflowLatestRun -RepositoryOwner 'Azure' -RepositoryName 'bicep-registry-modules' -WorkflowId '447791597' + +Get the latest workflow run of the repository [Azure/bicep-registry-modules] for a workflow with id '447791597', filtered to the 'main' branch. +#> +function Get-GitHubModuleWorkflowLatestRun { + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [string] $PersonalAccessToken, + + [Parameter(Mandatory = $true)] + [string] $RepositoryOwner, + + [Parameter(Mandatory = $true)] + [string] $RepositoryName, + + [Parameter(Mandatory = $true)] + [string] $WorkflowId, + + [Parameter(Mandatory = $false)] + [string] $TargetBranch = 'main' + ) + + $queryUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/workflows/$WorkflowId/runs?branch=$TargetBranch&per_page=1" + if ($PersonalAccessToken) { + # Using PAT + $requestInputObject = @{ + Method = 'GET' + Uri = "https://api.github.com$queryUrl" + Headers = @{ + Authorization = "Bearer $PersonalAccessToken" + } + } + $response = Invoke-RestMethod @requestInputObject + } else { + # Using GH API instead of 'gh workflow list' to get all results instead of just the first few + $requestInputObject = @( + '-H', 'Accept: application/vnd.github+json', + '-H', 'X-GitHub-Api-Version: 2022-11-28', + $queryUrl + ) + $response = (gh api @requestInputObject | ConvertFrom-Json) + } + + if (-not $response.workflow_runs) { + Write-Error "Request failed. Reponse: [$response]" + } + + return $response.workflow_runs | Select-Object -Property @('id', 'name', 'path', 'status', 'head_branch', 'created_at', 'run_number', 'run_attempt', 'conclusion') +} + +<# +.SYNOPSIS +Invoke the 'Rerun failed jobs' action for a given GitHub workflow run. + +.DESCRIPTION +Invoke the 'Rerun failed jobs' action for a given GitHub workflow run. + +.PARAMETER PersonalAccessToken +Optional. The PAT to use to interact with either GitHub. If not provided, the script will use the GitHub CLI to authenticate. + +.PARAMETER RepositoryOwner +Optional. The GitHub organization to run the workfows in. + +.PARAMETER RepositoryName +Optional. The GitHub repository to run the workfows in. + +.PARAMETER RunId +Mandatory. The ID of the run to re-run the failed jobs for. + +.EXAMPLE +Invoke-GitHubWorkflowRunFailedJobsReRun -RepositoryOwner 'Azure' -RepositoryName 'bicep-registry-modules' -RunId '447791597' + +Re-run the failed jobs for the GitHub workflow run with ID '447791597' in the repository [Azure/bicep-registry-modules]. +#> +function Invoke-GitHubWorkflowRunFailedJobsReRun { + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [string] $PersonalAccessToken, + + [Parameter(Mandatory = $true)] + [string] $RepositoryOwner, + + [Parameter(Mandatory = $true)] + [string] $RepositoryName, + + [Parameter(Mandatory = $true)] + [string] $RunId + ) + + + $queryUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/runs/$RunId/rerun-failed-jobs" + if ($PersonalAccessToken) { + # Using PAT + $requestInputObject = @{ + Method = 'POST' + Uri = "https://api.github.com$queryUrl" + Headers = @{ + Authorization = "Bearer $PersonalAccessToken" + } + } + $response = Invoke-RestMethod @requestInputObject + } else { + # Using GH API instead of 'gh workflow list' to get all results instead of just the first few + $requestInputObject = @( + '--method', 'POST', + '-H', 'Accept: application/vnd.github+json', + '-H', 'X-GitHub-Api-Version: 2022-11-28', + $queryUrl + ) + $response = (gh api @requestInputObject | ConvertFrom-Json) + } + + if ("$response") { + # If successfull, the response will be an empty custom object. Must be casted to string + Write-Error "Request failed. Response: [$response]" + return $false + } + + return $true +} +#endregion + +<# +.SYNOPSIS +Re-runs all failed jobs across all workflows for a given GitHub repository. + +.DESCRIPTION +Re-runs all failed jobs across all workflows for a given GitHub repository. +By default, pipelines are filtered to AVM module pipelines & the main branch. +Currently running workflows are excluded. + +.PARAMETER PersonalAccessToken +Optional. The PAT to use to interact with either GitHub. If not provided, the script will use the GitHub CLI to authenticate. + +.PARAMETER TargetBranch +Optional. The branch to run the pipelines for (e.g. `main`). Defaults to 'main'. + +.PARAMETER PipelineFilter +Optional. The pipeline files to filter down to (regex). + +.PARAMETER RepositoryOwner +Optional. The GitHub organization to run the workfows in. + +.PARAMETER RepositoryName +Optional. The GitHub repository to run the workfows in. + +.EXAMPLE +Invoke-WorkflowsFailedJobsReRun -PersonalAccessToken '' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' + +Run the failed jobs for all GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'. + +.EXAMPLE +Invoke-WorkflowsFailedJobsReRun -PersonalAccessToken '' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' -WhatIf + +Only simulate the triggering of the failed jobs for all failed GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'. + +.EXAMPLE +Invoke-WorkflowsFailedJobsReRun -PersonalAccessToken '' -RepositoryOwner 'MyFork' + +Only simulate the triggering of the failed jobs of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.res|ptn|utl', using the main branch & PAT. + +.EXAMPLE +Invoke-WorkflowsFailedJobsReRun -RepositoryOwner 'MyFork' + +Only simulate the triggering of the failed jobs of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.res|ptn|utl', using the main branch & your current GH CLI login. +#> +function Invoke-WorkflowsFailedJobsReRun { + + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory = $false)] + [string] $PersonalAccessToken, + + [Parameter(Mandatory = $false)] + [string] $TargetBranch = 'main', + + [Parameter(Mandatory = $false)] + [string] $PipelineFilter = 'avm\.(?:res|ptn|utl)', + + [Parameter(Mandatory = $false)] + [string] $RepositoryOwner = 'Azure', + + [Parameter(Mandatory = $false)] + [string] $RepositoryName = 'bicep-registry-modules' + ) + + $baseInputObject = @{ + RepositoryOwner = $RepositoryOwner + RepositoryName = $RepositoryName + } + if ($PersonalAccessToken) { + $baseInputObject['PersonalAccessToken'] = @{ + PersonalAccessToken = $PersonalAccessToken + } + } + ##################################### + # Get all workflows for branch # + ##################################### + Write-Verbose 'Fetching current GitHub workflows' -Verbose + $workflows = Get-GitHubModuleWorkflowList @baseInputObject -Filter $PipelineFilter + Write-Verbose ('Fetched [{0}] workflows' -f $workflows.Count) -Verbose + + + ###################################################### + # Analyze latest run of each workflow for branch # + ###################################################### + $totalCount = $workflows.Count + $currentCount = 1 + $runsToReTrigger = [System.Collections.ArrayList]@() + foreach ($workflow in $workflows) { + + $percentageComplete = [math]::Round(($currentCount / $totalCount) * 100) + Write-Progress -Activity ('Analyzing workflow [{0}]' -f $workflow.name) -Status "$percentageComplete% complete" -PercentComplete $percentageComplete + # Get relevant runs + $latestBranchRun = Get-GitHubModuleWorkflowLatestRun @baseInputObject -WorkflowId $workflow.id -TargetBranch $TargetBranch + + if ($latestBranchRun.status -eq 'completed' -and $latestBranchRun.conclusion -eq 'failure') { + $runsToReTrigger += $latestBranchRun + } + $currentCount++ + } + + ############################## + # Re-trigger failed runs # + ############################## + $reRunInputObject = @{ + RestInputObject = $baseInputObject + RunsToReTrigger = $runsToReTrigger + TotalNumberOfWorkflows = $workflows.Count + } + $null = Invoke-ReRun @reRunInputObject -WhatIf:$WhatIfPreference + + # Enable the user to execute the invocation if the whatif looked good + if ($WhatIfPreference) { + do { + $userInput = Read-Host -Prompt 'Should apply (y/n)?' + } + while ($userInput -notin @('y', 'n')) + + switch ($userInput) { + 'y' { + $null = Invoke-ReRun @reRunInputObject -WhatIf:$false + } + 'n' { return } + } + } + + Write-Verbose 'Re-triggerung complete' -Verbose +}