From 673d1836825cf8ff1fe072f3fb17d6fbc0c7c412 Mon Sep 17 00:00:00 2001 From: danielscholl Date: Wed, 14 Feb 2024 19:05:43 -0600 Subject: [PATCH] Refactored the solution bicep for better organization (#51) * Validated the capability with a s2s VPN solution. * Refactored the solution to leverage a better bicep pattern. --- .github/parameters.json | 12 - CONTRIBUTING.md | 76 + README.md | 50 +- azure.yaml | 35 + azuredeploy.json | 38699 ++++++++++++------------- bicep/main.bicep | 2010 +- bicep/main.parameters.json | 66 +- bicep/modules/blade_common.bicep | 360 + bicep/modules/blade_manage.bicep | 126 + bicep/modules/blade_network.bicep | 405 + bicep/modules/blade_partition.bicep | 378 + bicep/modules/blade_service.bicep | 518 + bicep/modules/keyvault_secrets.bicep | 16 +- bicep/modules/virtual_machine.bicep | 2 + bicepconfig.json | 59 +- docs/vnet-injection.md | 73 +- scripts/Dockerfile-provision | 23 + scripts/functions.sh | 73 + scripts/hook-preprovision.sh | 181 + 19 files changed, 21906 insertions(+), 21256 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 bicep/modules/blade_common.bicep create mode 100644 bicep/modules/blade_manage.bicep create mode 100644 bicep/modules/blade_network.bicep create mode 100644 bicep/modules/blade_partition.bicep create mode 100644 bicep/modules/blade_service.bicep create mode 100644 scripts/Dockerfile-provision create mode 100755 scripts/functions.sh create mode 100755 scripts/hook-preprovision.sh diff --git a/.github/parameters.json b/.github/parameters.json index 2f47a201..17fa2ccf 100644 --- a/.github/parameters.json +++ b/.github/parameters.json @@ -4,18 +4,6 @@ "parameters": { "applicationClientId": { "value": "00000000-0000-0000-0000-000000000000" - }, - "enableTelemetry": { - "value": false - }, - "enablePodSubnet": { - "value": false - }, - "enableVpnGateway": { - "value": false - }, - "enableBastion": { - "value": false } } } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..6fd07049 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +# Contributing to [project-title] + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + + - [Code of Conduct](#coc) + - [Issues and Bugs](#issue) + - [Feature Requests](#feature) + - [Submission Guidelines](#submit) + +## Code of Conduct +Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +## Found an Issue? +If you find a bug in the source code or a mistake in the documentation, you can help us by +[submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can +[submit a Pull Request](#submit-pr) with a fix. + +## Want a Feature? +You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub +Repository. If you would like to *implement* a new feature, please submit an issue with +a proposal for your work first, to be sure that we can use it. + +* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). + +## Submission Guidelines + +### Submitting an Issue +Before you submit an issue, search the archive, maybe your question was already answered. + +If your issue appears to be a bug, and hasn't been reported, open a new issue. +Help us to maximize the effort we can spend fixing issues and adding new +features, by not reporting duplicate issues. Providing the following information will increase the +chances of your issue being dealt with quickly: + +* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps +* **Version** - what version is affected (e.g. 0.1.2) +* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you +* **Browsers and Operating System** - is this a problem with all browsers? +* **Reproduce the Error** - provide a live example or a unambiguous set of steps +* **Related Issues** - has a similar issue been reported before? +* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be + causing the problem (line of code or commit) + +You can file new issues by providing the above information at the issues link: https://github.com/azure/osdu-develoepr/issues/new. + +### Submitting a Pull Request (PR) +Before you submit your Pull Request (PR) consider the following guidelines: + +* Search the repository (https://github.com/azure/osdu-developer/pulls) for an open or closed PR + that relates to your submission. You don't want to duplicate effort. + +* Make your changes in a new git fork: + +* Commit your changes using a descriptive commit message +* Push your fork to GitHub: +* In GitHub, create a pull request +* If we suggest changes then: + * Make the required updates. + * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): + + ```shell + git rebase master -i + git push -f + ``` + +That's it! Thank you for your contribution! diff --git a/README.md b/README.md index 9b3f0625..b70ba910 100644 --- a/README.md +++ b/README.md @@ -160,54 +160,44 @@ azd env set SOFTWARE_BRANCH main Customize your resources by enabling these optional features based on your specific requirements: -#### Feature: Pod Subnet +#### Feature: Vnet Injection -__Purpose:__ Enhances network configuration for Kubernetes Pods. +__Purpose:__ Enables a bring your own network capability. -__Details:__ Typically, with kubenet in Kubernetes, nodes are assigned IP addresses from the Azure virtual network subnet. Enabling the Pod Subnet feature allows Pods to receive IP addresses from a different address space, separate from the subnet of the nodes. This separation alters the network flows. +__Details:__ Typically, internal solutions require a preconfigured network due to possible S2S vpn configurations or a Hub Spoke Network design. __How To Enable:__ ```bash -azd env set ENABLE_POD_SUBNET true +azd env set ENABLE_VNET_INJECTION true ``` -#### Feature: Bastion +#### Feature: Pod Subnet -__Purpose:__ Facilitates secure access to internal network resources. +__Purpose:__ Enhances network configuration for Kubernetes Pods. -__Details:__ Internal ingress configurations can sometimes make it challenging to access network resources. The Bastion feature addresses this by creating a bastion host and a virtual machine. These components act as a secure gateway, allowing you to communicate with and manage resources within the private network, even if they're not exposed to the public internet. +__Details:__ Typically, with kubenet in Kubernetes, nodes are assigned IP addresses from the Azure virtual network subnet. Enabling the Pod Subnet feature allows Pods to receive IP addresses from a different address space, separate from the subnet of the nodes. This separation alters the network flows. __How To Enable:__ ```bash -azd env set ENABLE_BASTION true +azd env set ENABLE_POD_SUBNET true ``` -#### Feature: VPN Gateway - -__Purpose:__ Establishes secure VPN connections for remote access. - -__Details:__ The VPN Gateway feature is essential for projects that require secure remote network access. It facilitates the creation of site-to-site and point-to-site VPN connections, enabling secure and flexible development environments, especially when dealing with internal ingress. This feature is crucial for maintaining robust network security and facilitating seamless remote access. +#### Feature: Bastion -__Additional Configuration Values:__ +__Purpose:__ Facilitates secure access to internal network resources. -- REMOTE_NETWORK_PREFIX: The CIDR notation for the remote network (e.g., '192.168.1.0/24'). -- REMOTE_VPN_ADDRESS: The IP address of the Remote VPN Gateway. -- VPN_SHARED_KEY: The shared key for establishing the VPN connection. +__Details:__ Internal ingress configurations can sometimes make it challenging to access network resources. The Bastion feature addresses this by creating a bastion host and a virtual machine. These components act as a secure gateway, allowing you to communicate with and manage resources within the private network, even if they're not exposed to the public internet. __How To Enable:__ ```bash -azd env set ENABLE_VPN_GATEWAY true -azd env set REMOTE_NETWORK_PREFIX -azd env set REMOTE_VPN_ADDRESS -azd env set _VPN_SHARED_KEY +azd env set ENABLE_BASTION true ``` - #### Feature: Public Blob Access __Purpose:__ Control public access to Blob Storage. @@ -258,7 +248,7 @@ The architecture diagram below provides a visual representation of the infrastru 1. Azure Virtual Network: Illustrates the network and how feature enablement changes the network structure and subnets. 2. Azure Kubernetes Service (AKS): Demonstrates the Kubernetes clusters and an example of how software is set up along with interactions to other Azure services. 3. Storage Resources: Illustrates the use of services such as Azure Storage Accounts and Azure Cosmos Databases and how they connect to the network. -4. Optional Features: If enabled, features like the VPN Gateway, Bastion Host, and Pod Subnet are represented, attempting to show their placement and role within the architecture. +4. Optional Features: If enabled, features like the Bastion Host, Public Blob Access and Pod Subnet are represented, attempting to show their placement and role within the architecture. ## Software Management with a Gitops Approach @@ -289,20 +279,6 @@ There are many things that can be done to customize the deployment. One example See [this tutorial](docs/vnet-injection.md) for how a customization like this might be performed. -## Contributing - -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. - -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - ## Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft diff --git a/azure.yaml b/azure.yaml index 8ee1a54e..017182cb 100644 --- a/azure.yaml +++ b/azure.yaml @@ -6,3 +6,38 @@ metadata: infra: provider: bicep path: bicep +hooks: + preprovision: + posix: + interactive: false + continueOnError: false + shell: sh + run: | + # Check if PREPARE is not set to true + if [[ "$PREPARE" == "true" ]]; then + # Check if Docker command exists + if command -v docker &> /dev/null; then + echo "Building Docker Image" + docker buildx build --no-cache -f scripts/Dockerfile-provision -t azd-provision scripts + docker run --rm -v $(pwd):/workspace -v "${HOME}/.azure:/root/.azure" -e AZURE_CONFIG_DIR=/root/.azure azd-provision /usr/local/bin/preprovision.sh -s ${AZURE_SUBSCRIPTION_ID} + sleep 5 + else + echo "Docker is not installed." + exit 1 + fi + fi + + # windows: + # interactive: false + # continueOnError: false + # shell: pwsh + # run: | + # if (-Not (Get-Command "docker" -ErrorAction SilentlyContinue)) + # { + # Write-Host "no docker" + # exit + # } + # Write-Host "Building Docker Image" + # docker buildx build --no-cache -f scripts/Dockerfile-provision -t azd-provision scripts + # docker run --rm -v ${pwd}:/workspace -v "$($HOME)/.azure:/root/.azure" -e AZURE_CONFIG_DIR=/root/.azure azd-provision /usr/local/bin/preprovision.sh -s $env:AZURE_SUBSCRIPTION_ID + # Start-Sleep -Seconds 5 diff --git a/azuredeploy.json b/azuredeploy.json index 7b8c4ae0..8299f8aa 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -1,120 +1,201 @@ { "$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.24.24.22086", - "templateHash": "10551897021646849986" + "version": "0.25.53.49325", + "templateHash": "4658233491102570459" } }, - "parameters": { - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Specify the Azure region to place the application definition." - } - }, - "applicationClientId": { - "type": "string", - "metadata": { - "description": "Specify the AD Application Client Id." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Feature Flag to Enable Telemetry" - } - }, - "enablePrivateLink": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Feature Flag to Enable Private Link" - } - }, - "cmekConfiguration": { + "definitions": { + "bladeSettings": { "type": "object", - "defaultValue": { - "kvUrl": "", - "keyName": "", - "identityId": "" - }, - "metadata": { - "description": "Optional. Customer Managed Encryption Key." + "properties": { + "sectionName": { + "type": "string", + "metadata": { + "description": "The name of the section name" + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "The display name of the section" + } + } } }, - "enableVirtualWAN": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Feature Flag to Enable VPN Gateway Functionality" + "subnetSettings": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the subnet" + } + }, + "prefix": { + "type": "string", + "metadata": { + "description": "The address range to use for the subnet" + } + } } }, - "virtualNetworkAddressPrefix": { - "type": "string", - "defaultValue": "10.1.0.0/16", - "metadata": { - "description": "VNet address prefix" + "vnetSettings": { + "type": "object", + "properties": { + "group": { + "type": "string", + "metadata": { + "description": "The name of the resource group that contains the Virtual Network" + } + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Virtual Network" + } + }, + "prefix": { + "type": "string", + "metadata": { + "description": "The address range to use for the Virtual Network" + } + }, + "identityId": { + "type": "string", + "metadata": { + "description": "The Managed Identity " + } + }, + "aksSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The cluster subnet" + } + }, + "podSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The pod subnet" + } + }, + "vmSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The machine subnet" + } + }, + "bastionSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The bastion subnet" + } + } } }, - "aksSubnetName": { + "ingressType": { "type": "string", - "defaultValue": "ClusterSubnet", - "metadata": { - "description": "New or Existing subnet Name" - } + "allowedValues": [ + "Both", + "External", + "Internal" + ] }, - "aksSubnetAddressPrefix": { + "networkPluginType": { "type": "string", - "defaultValue": "10.1.0.0/20", - "metadata": { - "description": "Subnet address prefix" - } - }, - "enableVpnGateway": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Feature Flag to Enable VPN Gateway Functionality" - } + "allowedValues": [ + "azure", + "kubenet" + ] }, - "vpnSharedKey": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Shared Key for VPN Gateway" + "clusterNetworkType": { + "type": "object", + "properties": { + "networkPlugin": { + "$ref": "#/definitions/networkPluginType", + "metadata": { + "description": "The type of network plugin to use for the cluster" + } + }, + "ingress": { + "$ref": "#/definitions/ingressType", + "metadata": { + "description": "The type of ingress to use for the cluster" + } + }, + "serviceCidr": { + "type": "string", + "minLength": 9, + "maxLength": 18, + "metadata": { + "description": "The address range to use for services" + } + }, + "dockerBridgeCidr": { + "type": "string", + "minLength": 9, + "maxLength": 18, + "metadata": { + "description": "The address range to use for the docker bridge" + } + }, + "dnsServiceIP": { + "type": "string", + "minLength": 7, + "maxLength": 15, + "metadata": { + "description": "The IP address to reserve for DNS" + } + } } }, - "remoteVpnAddress": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "IP Address of the Remote VPN Gateway" + "softwareType": { + "type": "object", + "properties": { + "enable": { + "type": "bool", + "metadata": { + "description": "Feature Flag to Load Software." + } + }, + "repository": { + "type": "string", + "metadata": { + "description": "The URL of the software repository" + } + }, + "branch": { + "type": "string", + "metadata": { + "description": "The branch of the software repository" + } + } } - }, - "remoteNetworkPrefix": { + } + }, + "parameters": { + "location": { "type": "string", - "defaultValue": "192.168.1.0/24", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "IP Address Segment of the Remote Network" + "description": "Specify the Azure region to place the application definition." } }, - "gatewaySubnetName": { + "applicationClientId": { "type": "string", - "defaultValue": "GatewaySubnet", "metadata": { - "description": "New or Existing subnet Name" + "description": "Specify the AD Application Client Id." } }, - "gatewaySubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.1.17.0/24", + "enableTelemetry": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Specifies the Bastion subnet IP prefix. This prefix must be within vnet IP prefix address space." + "description": "Feature Flag to Enable Telemetry" } }, "enableBastion": { @@ -124,34 +205,6 @@ "description": "Feature Flag to Enable Bastion" } }, - "bastionSubnetName": { - "type": "string", - "defaultValue": "AzureBastionSubnet", - "metadata": { - "description": "New or Existing subnet Name" - } - }, - "bastionSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.1.16.0/24", - "metadata": { - "description": "Specifies the Bastion subnet IP prefix. This prefix must be within vnet IP prefix address space." - } - }, - "vmSubnetName": { - "type": "string", - "defaultValue": "VmSubnet", - "metadata": { - "description": "Specifies the name of the subnet which contains the virtual machine." - } - }, - "vmSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.1.18.0/24", - "metadata": { - "description": "Specifies the address prefix of the subnet which contains the virtual machine." - } - }, "enablePodSubnet": { "type": "bool", "defaultValue": false, @@ -159,73 +212,64 @@ "description": "Feature Flag to Enable a Pod Subnet" } }, - "podSubnetName": { - "type": "string", - "defaultValue": "PodSubnet", - "metadata": { - "description": "New or Existing subnet Name" - } - }, - "podSubnetAddressPrefix": { - "type": "string", - "defaultValue": "10.1.20.0/22", - "metadata": { - "description": "Subnet address prefix" - } - }, - "virtualNetworkNewOrExisting": { - "type": "string", - "defaultValue": "new", - "metadata": { - "description": "Boolean indicating whether the VNet is new or existing" - } - }, - "virtualNetworkName": { - "type": "string", - "defaultValue": "osdu-network", - "metadata": { - "description": "Name of the Virtual Network (Optional: If exiting Network is selected)" - } - }, - "virtualNetworkResourceGroup": { - "type": "string", - "defaultValue": "osdu-network", + "enableVnetInjection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Resource group of the VNet (Optional: If exiting Network is selected)" + "description": "Feature Flag to Enable a Pod Subnet" } }, - "serviceCidr": { - "type": "string", - "defaultValue": "172.16.0.0/16", - "minLength": 9, - "maxLength": 18, + "vnetConfiguration": { + "$ref": "#/definitions/vnetSettings", + "defaultValue": { + "group": "", + "name": "", + "prefix": "", + "identityId": "", + "aksSubnet": { + "name": "", + "prefix": "" + }, + "podSubnet": { + "name": "", + "prefix": "" + }, + "vmSubnet": { + "name": "", + "prefix": "" + }, + "bastionSubnet": { + "name": "", + "prefix": "" + } + }, "metadata": { - "description": "The address range to use for services" + "description": "Optional. Bring your own Virtual Network." } }, - "dockerBridgeCidr": { - "type": "string", - "defaultValue": "172.17.0.1/16", - "minLength": 9, - "maxLength": 18, + "enableBlobPublicAccess": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The address range to use for the docker bridge" + "description": "Optional. Indicates whether public access is enabled for all blobs or containers in the storage account." } }, - "dnsServiceIP": { - "type": "string", - "defaultValue": "172.16.0.10", - "minLength": 7, - "maxLength": 15, + "enablePrivateLink": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The IP address to reserve for DNS" + "description": "Feature Flag to Enable Private Link" } }, - "enableBlobPublicAccess": { - "type": "bool", - "defaultValue": true, + "cmekConfiguration": { + "type": "object", + "defaultValue": { + "kvUrl": "", + "keyName": "", + "identityId": "" + }, "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." + "description": "Optional. Customer Managed Encryption Key." } }, "vmAdminUsername": { @@ -242,7 +286,7 @@ "description": "Specifies the SSH Key or password for the virtual machine. SSH key is recommended." } }, - "clusterSize": { + "solutionTier": { "type": "string", "defaultValue": "CostOptimised", "allowedValues": [ @@ -251,7 +295,7 @@ "HighSpec" ], "metadata": { - "description": "The Cluster Size" + "description": "The size of the solution" } }, "partitions": { @@ -265,30 +309,28 @@ "description": "List of Data Partitions" } }, - "softwareRepository": { - "type": "string", - "defaultValue": "https://github.com/azure/osdu-developer", - "metadata": { - "description": "Software GIT Repository URL" - } - }, - "softwareBranch": { - "type": "string", - "defaultValue": "main", + "clusterNetworkProperties": { + "$ref": "#/definitions/clusterNetworkType", + "defaultValue": { + "networkPlugin": "[if(parameters('enablePodSubnet'), 'azure', 'kubenet')]", + "ingress": "Both", + "serviceCidr": "172.16.0.0/16", + "dockerBridgeCidr": "172.17.0.1/16", + "dnsServiceIP": "172.16.0.10" + }, "metadata": { - "description": "Software GIT Repository Branch" + "description": "Cluster Network Properties" } }, - "clusterIngress": { - "type": "string", - "defaultValue": "Both", - "allowedValues": [ - "Internal", - "External", - "Both" - ], + "clusterSoftwareProperties": { + "$ref": "#/definitions/softwareType", + "defaultValue": { + "enable": true, + "repository": "", + "branch": "" + }, "metadata": { - "description": "The Cluster Ingress Mode" + "description": "Cluster Software Properties" } }, "clusterAdminIds": { @@ -300,9 +342,9 @@ } }, "variables": { - "commonLayerConfig": { - "name": "common", - "displayName": "Common Resources", + "configuration": { + "name": "main", + "displayName": "Main Resources", "secrets": { "tenantId": "tenant-id", "subscriptionId": "subscription-id", @@ -323,506 +365,14 @@ "logs": { "sku": "PerGB2018", "retention": 30 - }, - "storage": { - "sku": "Standard_LRS", - "tables": [ - "partitionInfo" - ], - "shares": [ - "crs", - "crs-conversion", - "unit", - "sample-share" - ] - }, - "database": { - "name": "graph-db", - "throughput": 2000, - "backup": "Continuous", - "graphs": [ - { - "name": "Entitlements", - "automaticIndexing": true, - "partitionKeyPaths": [ - "/dataPartitionId" - ] - } - ] - } - }, - "nsgRules": { - "ssh_outbound": { - "name": "AllowSshOutbound", - "properties": { - "priority": 110, - "protocol": "*", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "22", - "3389" - ] - } - }, - "cloud_outbound": { - "name": "AllowAzureCloudOutbound", - "properties": { - "priority": 120, - "protocol": "Tcp", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "AzureCloud", - "destinationPortRange": "443" - } - }, - "bastion_communication": { - "name": "AllowBastionCommunication", - "properties": { - "priority": 130, - "protocol": "*", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "8080", - "5701" - ] - } - }, - "allow_http_outbound": { - "name": "AllowHttpOutbound", - "properties": { - "priority": 140, - "protocol": "*", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "Internet", - "destinationPortRange": "80" - } - }, - "gateway_manager_inbound": { - "name": "AllowGatewayManagerInbound", - "properties": { - "priority": 150, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "GatewayManager", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "443" - } - }, - "load_balancer_inbound": { - "name": "AllowAzureLoadBalancerInbound", - "properties": { - "priority": 160, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "AzureLoadBalancer", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "443" - } - }, - "bastion_host_communication": { - "name": "AllowBastionHostCommunication", - "properties": { - "priority": 170, - "protocol": "*", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "8080", - "5701" - ] - } - }, - "http_inbound_rule": { - "name": "AllowHttpInbound", - "properties": { - "priority": 200, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "Internet", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "80" - } - }, - "https_inbound_rule": { - "name": "AllowHttpsInbound", - "properties": { - "priority": 210, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "Internet", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "443" - } - }, - "ssh_inbound": { - "name": "AllowSshInbound", - "properties": { - "priority": 220, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "22", - "3389" - ] - } - } - }, - "vaultDNSZoneName": "privatelink.vaultcore.azure.net", - "vaultSecrets": [ - { - "secretName": "[variables('commonLayerConfig').secrets.tenantId]", - "secretValue": "[subscription().tenantId]" - }, - { - "secretName": "[variables('commonLayerConfig').secrets.subscriptionId]", - "secretValue": "[subscription().subscriptionId]" - }, - { - "secretName": "[variables('commonLayerConfig').secrets.clientId]", - "secretValue": "[parameters('applicationClientId')]" - }, - { - "secretName": "[variables('commonLayerConfig').secrets.applicationPrincipalId]", - "secretValue": "[parameters('applicationClientId')]" - } - ], - "storageDNSZoneForwarder": "[format('blob.{0}', environment().suffixes.storage)]", - "storageDnsZoneName": "[format('privatelink.{0}', variables('storageDNSZoneForwarder'))]", - "cosmosDnsZoneName": "privatelink.documents.azure.com", - "manageLayerConfig": { - "name": "manage", - "displayName": "Manage Resources", - "machine": { - "vmSize": "Standard_DS3_v2", - "imagePublisher": "Canonical", - "imageOffer": "UbuntuServer", - "imageSku": "18.04-LTS", - "authenticationType": "password" } - }, - "partitionLayerConfig": { - "name": "partition", - "displayName": "Data Partition Resources", - "secrets": { - "storageAccountName": "storage", - "storageAccountKey": "key", - "cosmosConnectionString": "cosmos-connection", - "cosmosEndpoint": "cosmos-endpoint", - "cosmosPrimaryKey": "cosmos-primary-key" - }, - "storage": { - "sku": "Standard_LRS", - "containers": [ - "legal-service-azure-configuration", - "osdu-wks-mappings", - "wdms-osdu", - "file-staging-area", - "file-persistent-area" - ] - }, - "database": { - "name": "osdu-db", - "CostOptimised": { - "throughput": 2000 - }, - "Standard": { - "throughput": 4000 - }, - "HighSpec": { - "throughput": 12000 - }, - "backup": "Continuous", - "containers": [ - { - "name": "LegalTag", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "StorageRecord", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "StorageSchema", - "kind": "Hash", - "paths": [ - "/kind" - ] - }, - { - "name": "TenantInfo", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "UserInfo", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "Authority", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "EntityType", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "SchemaInfo", - "kind": "Hash", - "paths": [ - "/partitionId" - ] - }, - { - "name": "Source", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "RegisterAction", - "kind": "Hash", - "paths": [ - "/dataPartitionId" - ] - }, - { - "name": "RegisterDdms", - "kind": "Hash", - "paths": [ - "/dataPartitionId" - ] - }, - { - "name": "RegisterSubscription", - "kind": "Hash", - "paths": [ - "/dataPartitionId" - ] - }, - { - "name": "IngestionStrategy", - "kind": "Hash", - "paths": [ - "/workflowType" - ] - }, - { - "name": "RelationshipStatus", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "MappingInfo", - "kind": "Hash", - "paths": [ - "/sourceSchemaKind" - ] - }, - { - "name": "FileLocationInfo", - "kind": "Hash", - "paths": [ - "/id" - ] - }, - { - "name": "WorkflowCustomOperatorInfo", - "kind": "Hash", - "paths": [ - "/operatorId" - ] - }, - { - "name": "WorkflowV2", - "kind": "Hash", - "paths": [ - "/partitionKey" - ] - }, - { - "name": "WorkflowRunV2", - "kind": "Hash", - "paths": [ - "/partitionKey" - ] - }, - { - "name": "WorkflowCustomOperatorV2", - "kind": "Hash", - "paths": [ - "/partitionKey" - ] - }, - { - "name": "WorkflowTasksSharingInfoV2", - "kind": "Hash", - "paths": [ - "/partitionKey" - ] - }, - { - "name": "Status", - "kind": "Hash", - "paths": [ - "/correlationId" - ] - }, - { - "name": "DataSetDetails", - "kind": "Hash", - "paths": [ - "/correlationId" - ] - } - ] - } - }, - "enableConfigMap": true, - "enableSoftwareLoad": true, - "serviceLayerConfig": { - "name": "service", - "displayName": "Service Resources", - "cluster": { - "aksVersion": "1.28", - "meshVersion": "asm-1-18", - "networkPlugin": "[if(parameters('enablePodSubnet'), 'azure', 'kubenet')]" - }, - "gitops": { - "name": "flux-system", - "url": "[parameters('softwareRepository')]", - "branch": "[parameters('softwareBranch')]", - "components": "./stamp/components", - "applications": "./stamp/applications" - }, - "imageList": { - "None": [], - "M22": [ - "community.opengroup.org:5555/osdu/platform/system/partition/partition-v0-24-0:latest", - "community.opengroup.org:5555/osdu/platform/security-and-compliance/entitlements/entitlements-v0-24-0:latest", - "community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/legal-v0-24-0:latest", - "community.opengroup.org:5555/osdu/platform/system/schema-service/schema-service-release-0-24:latest", - "community.opengroup.org:5555/osdu/platform/system/storage/storage-v0-24-0:latest", - "community.opengroup.org:5555/osdu/platform/system/file/file-v0-24-0:latest", - "community.opengroup.org:5555/osdu/platform/system/indexer-service/indexer-service-v0-24-0:latest", - "community.opengroup.org:5555/osdu/platform/system/search-service/search-service-v0-24-0:latest" - ] - } - }, - "elasticPoolPresets": { - "CostOptimised": { - "vmSize": "Standard_DS3_v2" - }, - "Standard": { - "vmSize": "Standard_DS4_v2" - }, - "HighSpec": { - "vmSize": "Standard_DS5_v2" - } - }, - "configMaps": { - "appConfigTemplate": "values.yaml: |\n serviceAccount:\n create: false\n name: \"workload-identity-sa\"\n azure:\n tenantId: {0}\n clientId: {1}\n configEndpoint: {2}\n keyvaultUri: {3}\n keyvaultName: {4}\n " } }, - "resources": [ - { - "condition": "[or(parameters('enableVirtualWAN'), parameters('enableVpnGateway'))]", - "type": "Microsoft.Network/virtualWans", - "apiVersion": "2023-06-01", - "name": "[format('wan-common{0}', uniqueString(resourceGroup().id, 'common'))]", - "location": "[parameters('location')]" - }, - { - "condition": "[or(parameters('enableVirtualWAN'), parameters('enableVpnGateway'))]", - "type": "Microsoft.Network/virtualHubs", - "apiVersion": "2023-06-01", - "name": "[format('hub-common{0}', uniqueString(resourceGroup().id, 'common'))]", - "location": "[parameters('location')]", - "properties": { - "virtualWan": { - "id": "[resourceId('Microsoft.Network/virtualWans', format('wan-common{0}', uniqueString(resourceGroup().id, 'common')))]" - }, - "addressPrefix": "[parameters('virtualNetworkAddressPrefix')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/virtualWans', format('wan-common{0}', uniqueString(resourceGroup().id, 'common')))]" - ] - }, - { - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('vaultDNSZoneName')]", - "location": "global", - "properties": {} - }, - { - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('storageDnsZoneName')]", - "location": "global", - "properties": {} - }, - { - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('cosmosDnsZoneName')]", - "location": "global", - "properties": {} - }, - { + "resources": { + "stampIdentity": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-user-managed-identity', variables('commonLayerConfig').name)]", + "name": "[format('{0}-user-managed-identity', variables('configuration').name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -830,7 +380,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('id-{0}{1}', replace(variables('commonLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('commonLayerConfig').name))]" + "value": "[format('id-{0}{1}', replace(variables('configuration').name, '-', ''), uniqueString(resourceGroup().id, variables('configuration').name))]" }, "location": { "value": "[parameters('location')]" @@ -840,7 +390,7 @@ }, "tags": { "value": { - "layer": "[variables('commonLayerConfig').displayName]" + "layer": "[variables('configuration').displayName]" } } }, @@ -1238,10 +788,10 @@ } } }, - { + "logAnalytics": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-log-analytics', variables('commonLayerConfig').name)]", + "name": "[format('{0}-log-analytics', variables('configuration').name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -1249,7 +799,7 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[format('log-{0}{1}', replace(variables('commonLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('commonLayerConfig').name))]" + "value": "[format('log-{0}{1}', replace(variables('configuration').name, '-', ''), uniqueString(resourceGroup().id, variables('configuration').name))]" }, "location": { "value": "[parameters('location')]" @@ -1259,11 +809,11 @@ }, "tags": { "value": { - "layer": "[variables('commonLayerConfig').displayName]" + "layer": "[variables('configuration').displayName]" } }, "skuName": { - "value": "[variables('commonLayerConfig').logs.sku]" + "value": "[variables('configuration').logs.sku]" } }, "template": { @@ -3044,24 +2594,23 @@ } } } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] + } }, - { - "condition": "[equals(parameters('virtualNetworkNewOrExisting'), 'new')]", + "networkBlade": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)]", + "name": "network-blade", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('nsg-common{0}-aks', uniqueString(resourceGroup().id, 'common'))]" + "bladeConfig": { + "value": { + "sectionName": "networkblade", + "displayName": "Network Resources" + } }, "location": { "value": "[parameters('location')]" @@ -3069,13 +2618,23 @@ "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } + "workspaceResourceId": { + "value": "[reference('logAnalytics').outputs.resourceId.value]" + }, + "identityId": { + "value": "[reference('stampIdentity').outputs.principalId.value]" + }, + "enableBastion": { + "value": "[parameters('enableBastion')]" + }, + "enablePodSubnet": { + "value": "[parameters('enablePodSubnet')]" + }, + "enableVnetInjection": { + "value": "[parameters('enableVnetInjection')]" }, - "securityRules": { - "value": "[union(array(variables('nsgRules').http_inbound_rule), array(variables('nsgRules').https_inbound_rule), array(variables('nsgRules').ssh_outbound))]" + "vnetConfiguration": { + "value": "[parameters('vnetConfiguration')]" } }, "template": { @@ -3085,388 +2644,296 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "9172306311946541571" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", - "owner": "Azure/module-maintainers" + "version": "0.25.53.49325", + "templateHash": "12025126694801882509" + } }, "definitions": { - "lockType": { + "bladeSettings": { + "type": "object", + "properties": { + "sectionName": { + "type": "string", + "metadata": { + "description": "The name of the section name" + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "The display name of the section" + } + } + } + }, + "subnetSettings": { "type": "object", "properties": { "name": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "The name of the subnet" } }, - "kind": { + "prefix": { "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, "metadata": { - "description": "Optional. Specify the type of lock." + "description": "The address range to use for the subnet" } } - }, - "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." - } + "vnetSettings": { + "type": "object", + "properties": { + "group": { + "type": "string", + "metadata": { + "description": "The name of the resource group that contains the Virtual Network" + } + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Virtual Network" + } + }, + "prefix": { + "type": "string", + "metadata": { + "description": "The address range to use for the Virtual Network" + } + }, + "identityId": { + "type": "string", + "metadata": { + "description": "The Managed Identity " + } + }, + "aksSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The cluster subnet" + } + }, + "podSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The pod subnet" + } + }, + "vmSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The machine subnet" + } + }, + "bastionSubnet": { + "$ref": "#/definitions/subnetSettings", + "metadata": { + "description": "The bastion subnet" } } - }, - "nullable": true + } + } + }, + "parameters": { + "bladeConfig": { + "$ref": "#/definitions/bladeSettings", + "metadata": { + "description": "The configuration for the blade section." + } }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", + "location": { + "type": "string", + "metadata": { + "description": "The location of resources to deploy" + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Feature Flag to Enable Telemetry" + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "The workspace resource Id for diagnostics" + } + }, + "vnetConfiguration": { + "$ref": "#/definitions/vnetSettings", + "metadata": { + "description": "Optional. Bring your own Virtual Network." + } + }, + "enableBastion": { + "type": "bool", + "metadata": { + "description": "Feature Flag to Enable Bastion" + } + }, + "enablePodSubnet": { + "type": "bool", + "metadata": { + "description": "Feature Flag to Enable a Pod Subnet" + } + }, + "enableVnetInjection": { + "type": "bool", + "metadata": { + "description": "Feature Flag to Enable a Pod Subnet" + } + }, + "identityId": { + "type": "string", + "metadata": { + "description": "The Managed Identity Principal Id" + } + } + }, + "variables": { + "networkConfiguration": "[if(equals(parameters('vnetConfiguration').name, ''), createObject('prefix', '10.1.0.0/16', 'aksSubnet', createObject('name', 'ClusterSubnet', 'prefix', '10.1.0.0/20'), 'podSubnet', createObject('name', 'PodSubnet', 'prefix', '10.1.20.0/22'), 'vmSubnet', createObject('name', 'VmSubnet', 'prefix', '10.1.18.0/24'), 'bastionSubnet', createObject('name', 'AzureBastionSubnet', 'prefix', '10.1.16.0/24')), parameters('vnetConfiguration'))]", + "nsgRules": { + "ssh_outbound": { + "name": "AllowSshOutbound", "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." - } - } - } - }, - "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." - } - } + "priority": 110, + "protocol": "*", + "access": "Allow", + "direction": "Outbound", + "sourceAddressPrefix": "*", + "sourcePortRange": "*", + "destinationAddressPrefix": "VirtualNetwork", + "destinationPortRanges": [ + "22", + "3389" + ] } }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "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 NSG resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{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" - } - } + "cloud_outbound": { + "name": "AllowAzureCloudOutbound", + "properties": { + "priority": 120, + "protocol": "Tcp", + "access": "Allow", + "direction": "Outbound", + "sourceAddressPrefix": "*", + "sourcePortRange": "*", + "destinationAddressPrefix": "AzureCloud", + "destinationPortRange": "443" } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{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": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + "bastion_communication": { + "name": "AllowBastionCommunication", + "properties": { + "priority": 130, + "protocol": "*", + "access": "Allow", + "direction": "Outbound", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*", + "destinationAddressPrefix": "VirtualNetwork", + "destinationPortRanges": [ + "8080", + "5701" + ] + } }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "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')]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + "allow_http_outbound": { + "name": "AllowHttpOutbound", + "properties": { + "priority": 140, + "protocol": "*", + "access": "Allow", + "direction": "Outbound", + "sourceAddressPrefix": "*", + "sourcePortRange": "*", + "destinationAddressPrefix": "Internet", + "destinationPortRange": "80" + } }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "load_balancer_inbound": { + "name": "AllowAzureLoadBalancerInbound", + "properties": { + "priority": 160, + "protocol": "Tcp", + "access": "Allow", + "direction": "Inbound", + "sourceAddressPrefix": "AzureLoadBalancer", + "sourcePortRange": "*", + "destinationAddressPrefix": "*", + "destinationPortRange": "443" + } }, - "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')]" + "bastion_host_communication": { + "name": "AllowBastionHostCommunication", + "properties": { + "priority": 170, + "protocol": "*", + "access": "Allow", + "direction": "Inbound", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*", + "destinationAddressPrefix": "VirtualNetwork", + "destinationPortRanges": [ + "8080", + "5701" + ] + } }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" + "http_inbound_rule": { + "name": "AllowHttpInbound", + "properties": { + "priority": 200, + "protocol": "Tcp", + "access": "Allow", + "direction": "Inbound", + "sourceAddressPrefix": "Internet", + "sourcePortRange": "*", + "destinationAddressPrefix": "*", + "destinationPortRange": "80" + } + }, + "https_inbound_rule": { + "name": "AllowHttpsInbound", + "properties": { + "priority": 210, + "protocol": "Tcp", + "access": "Allow", + "direction": "Inbound", + "sourceAddressPrefix": "Internet", + "sourcePortRange": "*", + "destinationAddressPrefix": "*", + "destinationPortRange": "443" + } }, + "ssh_inbound": { + "name": "AllowSshInbound", + "properties": { + "priority": 220, + "protocol": "Tcp", + "access": "Allow", + "direction": "Inbound", + "sourceAddressPrefix": "VirtualNetwork", + "sourcePortRange": "*", + "destinationAddressPrefix": "VirtualNetwork", + "destinationPortRanges": [ + "22", + "3389" + ] + } + } + } + }, + "resources": { + "clusterNetworkSecurityGroup": { + "condition": "[not(parameters('enableVnetInjection'))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-nsg-cluster', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -3474,2435 +2941,2556 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" + "value": "[format('nsg-common{0}-aks', uniqueString(resourceGroup().id, 'common'))]" }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', createArray()))]" + "securityRules": { + "value": "[union(array(variables('nsgRules').http_inbound_rule), array(variables('nsgRules').https_inbound_rule), array(variables('nsgRules').ssh_outbound))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.23.1.45101", - "templateHash": "13132940167196258311" + "templateHash": "9172306311946541571" }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", "owner": "Azure/module-maintainers" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "networkSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." - } - }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, - "metadata": { - "description": "Optional. A description for this rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } + "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 }, - "destinationAddressPrefixes": { + "roleAssignmentType": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } + "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 }, - "destinationApplicationSecurityGroups": { + "diagnosticSettingType": { "type": "array", - "defaultValue": [], + "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." + } + } + } + }, + "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": "Optional. The application security group specified as destination." + "description": "Required. Name of the Network Security Group." } }, - "destinationPortRange": { + "location": { "type": "string", - "defaultValue": "", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + "description": "Optional. Location for all resources." } }, - "destinationPortRanges": { + "securityRules": { "type": "array", "defaultValue": [], "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], + "flushConnection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Required. Network protocol this rule applies to." + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." } }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + "description": "Optional. The diagnostic settings of the service." } }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. The CIDR or source IP ranges." + "description": "Optional. The lock settings of the service." } }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. The application security group specified as source." + "description": "Optional. Array of role assignments to create." } }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + "description": "Optional. Tags of the NSG resource." } }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The source port ranges." + "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } } }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", - "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" - } + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } - ], + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{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" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" + } + }, + "networkSecurityGroup_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/networkSecurityGroups/{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": [ + "networkSecurityGroup" + ] + }, + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "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')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "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" + ] + }, + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityRules')[copyIndex()].name]" + }, + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', 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.23.1.45101", + "templateHash": "13132940167196258311" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "networkSecurityGroup" + ] + } + }, "outputs": { "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the security rule was deployed into." + "description": "The resource group the network security group was deployed into." }, "value": "[resourceGroup().name]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the security rule." + "description": "The resource ID of the network security group." }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" }, "name": { "type": "string", "metadata": { - "description": "The name of the security rule." + "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-04-01', 'full').location]" } } } - }, - "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-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[and(equals(parameters('virtualNetworkNewOrExisting'), 'new'), parameters('enableBastion'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-network-security-group-bastion', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('nsg-common{0}-bastion', uniqueString(resourceGroup().id, 'common'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "securityRules": { - "value": "[union(array(variables('nsgRules').https_inbound_rule), array(variables('nsgRules').gateway_manager_inbound), array(variables('nsgRules').load_balancer_inbound), array(variables('nsgRules').bastion_host_communication), array(variables('nsgRules').ssh_outbound), array(variables('nsgRules').cloud_outbound), array(variables('nsgRules').bastion_communication), array(variables('nsgRules').allow_http_outbound))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "9172306311946541571" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "lockType": { - "type": "object", + "bastionNetworkSecurityGroup": { + "condition": "[and(not(parameters('enableVnetInjection')), parameters('enableBastion'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-nsg-bastion', parameters('bladeConfig').sectionName)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "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." - } + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('nsg-common{0}-bastion', uniqueString(resourceGroup().id, 'common'))]" }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } + "location": { + "value": "[parameters('location')]" }, - "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\"." - } + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." - } + "securityRules": { + "value": "[union(array(variables('nsgRules').https_inbound_rule), array(variables('nsgRules').load_balancer_inbound), array(variables('nsgRules').bastion_host_communication), array(variables('nsgRules').ssh_outbound), array(variables('nsgRules').cloud_outbound), array(variables('nsgRules').bastion_communication), array(variables('nsgRules').allow_http_outbound))]" } - } - }, - "nullable": true - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "9172306311946541571" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", + "owner": "Azure/module-maintainers" }, - "logCategoriesAndGroups": { - "type": "array", - "items": { + "definitions": { + "lockType": { "type": "object", "properties": { - "category": { + "name": { "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." + "description": "Optional. Specify the name of lock." } }, - "categoryGroup": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "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." + "description": "Optional. Specify the type of lock." } } - } + }, + "nullable": 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 Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "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 NSG resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{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" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{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": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "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')]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", - "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" - ] - }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" - }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" - }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', 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.23.1.45101", - "templateHash": "13132940167196258311" - }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "networkSecurityGroupName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." - } - }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, - "metadata": { - "description": "Optional. A description for this rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroups": { + "roleAssignmentType": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } + "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 }, - "destinationPortRanges": { + "diagnosticSettingType": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { + "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." + } + } + } + }, + "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", - "allowedValues": [ - "Inbound", - "Outbound" - ], "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + "description": "Required. Name of the Network Security Group." } }, - "priority": { - "type": "int", + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + "description": "Optional. Location for all resources." } }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], + "securityRules": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. Network protocol this rule applies to." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", + "flushConnection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." } }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. The CIDR or source IP ranges." + "description": "Optional. The diagnostic settings of the service." } }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. The application security group specified as source." + "description": "Optional. The lock settings of the service." } }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + "description": "Optional. Array of role assignments to create." } }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the NSG resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The source port ranges." + "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } } }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{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" + } + } + } + } + }, + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the security rule was deployed into." + }, + "networkSecurityGroup_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/networkSecurityGroups/{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.')]" }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "networkSecurityGroup" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the security rule." + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "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')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + "dependsOn": [ + "networkSecurityGroup" + ] }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the security rule." + "networkSecurityGroup_roleAssignments": { + "copy": { + "name": "networkSecurityGroup_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" }, - "value": "[parameters('name')]" - } - } - } - }, - "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-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[and(equals(parameters('virtualNetworkNewOrExisting'), 'new'), parameters('enableBastion'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-network-security-group-manage', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('nsg-common{0}-vm', uniqueString(resourceGroup().id, 'common'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "securityRules": { - "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.23.1.45101", - "templateHash": "9172306311946541571" + "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" + ] + }, + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityRules')[copyIndex()].name]" + }, + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', 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.23.1.45101", + "templateHash": "13132940167196258311" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "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-04-01', 'full').location]" + } + } + } + } }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG).", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "lockType": { - "type": "object", + "machineNetworkSecurityGroup": { + "condition": "[and(not(parameters('enableVnetInjection')), parameters('enableBastion'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-nsg-manage', parameters('bladeConfig').sectionName)]", "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('nsg-common{0}-vm', uniqueString(resourceGroup().id, 'common'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } + }, + "securityRules": { + "value": [] } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", "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 - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "9172306311946541571" + }, + "name": "Network Security Groups", + "description": "This module deploys a Network security Group (NSG).", + "owner": "Azure/module-maintainers" }, - "logCategoriesAndGroups": { - "type": "array", - "items": { + "definitions": { + "lockType": { "type": "object", "properties": { - "category": { + "name": { "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." + "description": "Optional. Specify the name of lock." } }, - "categoryGroup": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "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." + "description": "Optional. Specify the type of lock." } } - } + }, + "nullable": 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 Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "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 NSG resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{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" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(parameters('securityRules'))]", - "input": { - "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", - "properties": { - "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", - "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", - "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", - "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", - "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{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": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "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')]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", - "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" - ] - }, - "networkSecurityGroup_securityRules": { - "copy": { - "name": "networkSecurityGroup_securityRules", - "count": "[length(parameters('securityRules'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('securityRules')[copyIndex()].name]" - }, - "networkSecurityGroupName": { - "value": "[parameters('name')]" - }, - "protocol": { - "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" - }, - "access": { - "value": "[parameters('securityRules')[copyIndex()].properties.access]" - }, - "priority": { - "value": "[parameters('securityRules')[copyIndex()].properties.priority]" - }, - "direction": { - "value": "[parameters('securityRules')[copyIndex()].properties.direction]" - }, - "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", - "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", - "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", - "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", - "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", - "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", - "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", - "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", - "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", - "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", - "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', 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.23.1.45101", - "templateHash": "13132940167196258311" + "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 }, - "name": "Network Security Group (NSG) Security Rules", - "description": "This module deploys a Network Security Group (NSG) Security Rule.", - "owner": "Azure/module-maintainers" + "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." + } + } + } + }, + "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. The name of the security rule." + "description": "Required. Name of the Network Security Group." } }, - "networkSecurityGroupName": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + "description": "Optional. Location for all resources." } }, - "access": { - "type": "string", - "defaultValue": "Deny", - "allowedValues": [ - "Allow", - "Deny" - ], + "securityRules": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Whether network traffic is allowed or denied." + "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." } }, - "description": { - "type": "string", - "defaultValue": "", - "maxLength": 140, + "flushConnection": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. A description for this rule." + "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." } }, - "destinationAddressPrefix": { - "type": "string", - "defaultValue": "", + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", "metadata": { - "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + "description": "Optional. The diagnostic settings of the service." } }, - "destinationAddressPrefixes": { - "type": "array", - "defaultValue": [], + "lock": { + "$ref": "#/definitions/lockType", "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + "description": "Optional. The lock settings of the service." } }, - "destinationApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "Optional. The application security group specified as destination." + "description": "Optional. Array of role assignments to create." } }, - "destinationPortRange": { - "type": "string", - "defaultValue": "", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + "description": "Optional. Tags of the NSG resource." } }, - "destinationPortRanges": { - "type": "array", - "defaultValue": [], + "enableTelemetry": { + "type": "bool", + "defaultValue": true, "metadata": { - "description": "Optional. The destination port ranges." + "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The CIDR or source IP ranges." + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networksecuritygroup.{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" + } + } + } } }, - "sourceApplicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The application security group specified as source." + "networkSecurityGroup": { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "securityRules", + "count": "[length(parameters('securityRules'))]", + "input": { + "name": "[parameters('securityRules')[copyIndex('securityRules')].name]", + "properties": { + "protocol": "[parameters('securityRules')[copyIndex('securityRules')].properties.protocol]", + "access": "[parameters('securityRules')[copyIndex('securityRules')].properties.access]", + "priority": "[parameters('securityRules')[copyIndex('securityRules')].properties.priority]", + "direction": "[parameters('securityRules')[copyIndex('securityRules')].properties.direction]", + "description": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'description'), parameters('securityRules')[copyIndex('securityRules')].properties.description, '')]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRange, '')]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourcePortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.sourcePortRanges, createArray())]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRange'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRange, '')]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationPortRanges'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationPortRanges, createArray())]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefix, '')]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefix, '')]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceAddressPrefixes, createArray())]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationAddressPrefixes, createArray())]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.sourceApplicationSecurityGroups, createArray())]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroups'), parameters('securityRules')[copyIndex('securityRules')].properties.destinationApplicationSecurityGroups, createArray())]" + } + } + } + ], + "flushConnection": "[parameters('flushConnection')]" } }, - "sourcePortRange": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } + "networkSecurityGroup_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/networkSecurityGroups/{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": [ + "networkSecurityGroup" + ] }, - "sourcePortRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkSecurityGroups/securityRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "networkSecurityGroup_diagnosticSettings": { + "copy": { + "name": "networkSecurityGroup_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", "properties": { - "access": "[parameters('access')]", - "description": "[parameters('description')]", - "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", - "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", - "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", - "destinationPortRange": "[parameters('destinationPortRange')]", - "destinationPortRanges": "[parameters('destinationPortRanges')]", - "direction": "[parameters('direction')]", - "priority": "[parameters('priority')]", - "protocol": "[parameters('protocol')]", - "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", - "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", - "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", - "sourcePortRange": "[parameters('sourcePortRange')]", - "sourcePortRanges": "[parameters('sourcePortRanges')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the security rule was deployed into." + "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')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "networkSecurityGroup" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the security rule." + "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')]" }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + "dependsOn": [ + "networkSecurityGroup" + ] }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the security rule." + "networkSecurityGroup_securityRules": { + "copy": { + "name": "networkSecurityGroup_securityRules", + "count": "[length(parameters('securityRules'))]" }, - "value": "[parameters('name')]" - } - } - } - }, - "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-04-01', 'full').location]" - } - } - } - } - }, - { - "condition": "[equals(parameters('virtualNetworkNewOrExisting'), 'new')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-virtual-network', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('vnet-common{0}', uniqueString(resourceGroup().id, 'common'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "addressPrefixes": { - "value": [ - "[parameters('virtualNetworkAddressPrefix')]" - ] - }, - "diagnosticSettings": { - "value": [ - { - "name": "LogAnalytics", - "workspaceResourceId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]", - "metricCategories": [ - { - "category": "AllMetrics" - } - ] - } - ] - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Reader", - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "subnets": { - "value": "[union(array(createObject('cluster', createObject('name', parameters('aksSubnetName'), 'addressPrefix', parameters('aksSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', parameters('podSubnetName'), 'addressPrefix', parameters('podSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', parameters('bastionSubnetName'), 'addressPrefix', parameters('bastionSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-bastion', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null())), 'gateway', createObject('name', parameters('gatewaySubnetName'), 'addressPrefix', parameters('gatewaySubnetAddressPrefix')), 'machine', createObject('name', parameters('vmSubnetName'), 'addressPrefix', parameters('vmSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-manage', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()))).cluster), if(parameters('enableBastion'), array(createObject('cluster', createObject('name', parameters('aksSubnetName'), 'addressPrefix', parameters('aksSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', parameters('podSubnetName'), 'addressPrefix', parameters('podSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', parameters('bastionSubnetName'), 'addressPrefix', parameters('bastionSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-bastion', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null())), 'gateway', createObject('name', parameters('gatewaySubnetName'), 'addressPrefix', parameters('gatewaySubnetAddressPrefix')), 'machine', createObject('name', parameters('vmSubnetName'), 'addressPrefix', parameters('vmSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-manage', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()))).bastion), createArray()), if(parameters('enableBastion'), array(createObject('cluster', createObject('name', parameters('aksSubnetName'), 'addressPrefix', parameters('aksSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', parameters('podSubnetName'), 'addressPrefix', parameters('podSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', parameters('bastionSubnetName'), 'addressPrefix', parameters('bastionSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-bastion', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null())), 'gateway', createObject('name', parameters('gatewaySubnetName'), 'addressPrefix', parameters('gatewaySubnetAddressPrefix')), 'machine', createObject('name', parameters('vmSubnetName'), 'addressPrefix', parameters('vmSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-manage', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()))).machine), createArray()), if(parameters('enableVpnGateway'), array(createObject('cluster', createObject('name', parameters('aksSubnetName'), 'addressPrefix', parameters('aksSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', parameters('podSubnetName'), 'addressPrefix', parameters('podSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', parameters('bastionSubnetName'), 'addressPrefix', parameters('bastionSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-bastion', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null())), 'gateway', createObject('name', parameters('gatewaySubnetName'), 'addressPrefix', parameters('gatewaySubnetAddressPrefix')), 'machine', createObject('name', parameters('vmSubnetName'), 'addressPrefix', parameters('vmSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-manage', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()))).gateway), createArray()), if(parameters('enablePodSubnet'), array(createObject('cluster', createObject('name', parameters('aksSubnetName'), 'addressPrefix', parameters('aksSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', parameters('podSubnetName'), 'addressPrefix', parameters('podSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value, 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', parameters('bastionSubnetName'), 'addressPrefix', parameters('bastionSubnetAddressPrefix'), 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-bastion', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null())), 'gateway', createObject('name', parameters('gatewaySubnetName'), 'addressPrefix', parameters('gatewaySubnetAddressPrefix')), 'machine', createObject('name', parameters('vmSubnetName'), 'addressPrefix', parameters('vmSubnetAddressPrefix'), 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-manage', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()))).pods), 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.21.1.54444", - "templateHash": "7839005038128499146" - }, - "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": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NetworkSecurityGroup-SecurityRule-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('securityRules')[copyIndex()].name]" + }, + "networkSecurityGroupName": { + "value": "[parameters('name')]" + }, + "protocol": { + "value": "[parameters('securityRules')[copyIndex()].properties.protocol]" + }, + "access": { + "value": "[parameters('securityRules')[copyIndex()].properties.access]" + }, + "priority": { + "value": "[parameters('securityRules')[copyIndex()].properties.priority]" + }, + "direction": { + "value": "[parameters('securityRules')[copyIndex()].properties.direction]" + }, + "description": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'description'), createObject('value', parameters('securityRules')[copyIndex()].properties.description), createObject('value', ''))]", + "sourcePortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRange), createObject('value', ''))]", + "sourcePortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourcePortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourcePortRanges), createObject('value', createArray()))]", + "destinationPortRange": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRange'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRange), createObject('value', ''))]", + "destinationPortRanges": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationPortRanges'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationPortRanges), createObject('value', createArray()))]", + "sourceAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefix), createObject('value', ''))]", + "destinationAddressPrefix": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefix'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefix), createObject('value', ''))]", + "sourceAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceAddressPrefixes), createObject('value', createArray()))]", + "destinationAddressPrefixes": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationAddressPrefixes'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationAddressPrefixes), createObject('value', createArray()))]", + "sourceApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'sourceApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.sourceApplicationSecurityGroups), createObject('value', createArray()))]", + "destinationApplicationSecurityGroups": "[if(contains(parameters('securityRules')[copyIndex()].properties, 'destinationApplicationSecurityGroups'), createObject('value', parameters('securityRules')[copyIndex()].properties.destinationApplicationSecurityGroups), createObject('value', 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.23.1.45101", + "templateHash": "13132940167196258311" + }, + "name": "Network Security Group (NSG) Security Rules", + "description": "This module deploys a Network Security Group (NSG) Security Rule.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the security rule." + } + }, + "networkSecurityGroupName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent network security group to deploy the security rule into. Required if the template is used in a standalone deployment." + } + }, + "access": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. Whether network traffic is allowed or denied." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "maxLength": 140, + "metadata": { + "description": "Optional. A description for this rule." + } + }, + "destinationAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." + } + }, + "destinationAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." + } + }, + "destinationApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as destination." + } + }, + "destinationPortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "destinationPortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The destination port ranges." + } + }, + "direction": { + "type": "string", + "allowedValues": [ + "Inbound", + "Outbound" + ], + "metadata": { + "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." + } + }, + "priority": { + "type": "int", + "metadata": { + "description": "Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "Ah", + "Esp", + "Icmp", + "Tcp", + "Udp" + ], + "metadata": { + "description": "Required. Network protocol this rule applies to." + } + }, + "sourceAddressPrefix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." + } + }, + "sourceAddressPrefixes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The CIDR or source IP ranges." + } + }, + "sourceApplicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The application security group specified as source." + } + }, + "sourcePortRange": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." + } + }, + "sourcePortRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The source port ranges." + } + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups/securityRules", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkSecurityGroupName'), parameters('name'))]", + "properties": { + "access": "[parameters('access')]", + "description": "[parameters('description')]", + "destinationAddressPrefix": "[parameters('destinationAddressPrefix')]", + "destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]", + "destinationApplicationSecurityGroups": "[parameters('destinationApplicationSecurityGroups')]", + "destinationPortRange": "[parameters('destinationPortRange')]", + "destinationPortRanges": "[parameters('destinationPortRanges')]", + "direction": "[parameters('direction')]", + "priority": "[parameters('priority')]", + "protocol": "[parameters('protocol')]", + "sourceAddressPrefix": "[parameters('sourceAddressPrefix')]", + "sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]", + "sourceApplicationSecurityGroups": "[parameters('sourceApplicationSecurityGroups')]", + "sourcePortRange": "[parameters('sourcePortRange')]", + "sourcePortRanges": "[parameters('sourcePortRanges')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the security rule was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the security rule." + }, + "value": "[resourceId('Microsoft.Network/networkSecurityGroups/securityRules', parameters('networkSecurityGroupName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the security rule." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "networkSecurityGroup" + ] } }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + "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-04-01', 'full').location]" } + } + } + } + }, + "network": { + "condition": "[not(parameters('enableVnetInjection'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-virtual-network', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('vnet-common{0}', uniqueString(resourceGroup().id, 'common'))]" }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } + "location": { + "value": "[parameters('location')]" }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." - } + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "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\"" + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } + "addressPrefixes": { + "value": [ + "[variables('networkConfiguration').prefix]" + ] }, - "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." - } + "diagnosticSettings": { + "value": [ + { + "name": "LogAnalytics", + "workspaceResourceId": "[parameters('workspaceResourceId')]", + "metricCategories": [ + { + "category": "AllMetrics" + } + ] + } + ] }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", + "roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "principalId": "[parameters('identityId')]", + "principalType": "ServicePrincipal" + } + ] + }, + "subnets": { + "value": "[union(array(createObject('cluster', createObject('name', variables('networkConfiguration').aksSubnet.name, 'addressPrefix', variables('networkConfiguration').aksSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', variables('networkConfiguration').podSubnet.name, 'addressPrefix', variables('networkConfiguration').podSubnet.prefix, 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', variables('networkConfiguration').bastionSubnet.name, 'addressPrefix', variables('networkConfiguration').bastionSubnet.prefix, 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('bastionNetworkSecurityGroup').outputs.resourceId.value, null())), 'machine', createObject('name', variables('networkConfiguration').vmSubnet.name, 'addressPrefix', variables('networkConfiguration').vmSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('machineNetworkSecurityGroup').outputs.resourceId.value, null()))).cluster), if(parameters('enablePodSubnet'), array(createObject('cluster', createObject('name', variables('networkConfiguration').aksSubnet.name, 'addressPrefix', variables('networkConfiguration').aksSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', variables('networkConfiguration').podSubnet.name, 'addressPrefix', variables('networkConfiguration').podSubnet.prefix, 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', variables('networkConfiguration').bastionSubnet.name, 'addressPrefix', variables('networkConfiguration').bastionSubnet.prefix, 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('bastionNetworkSecurityGroup').outputs.resourceId.value, null())), 'machine', createObject('name', variables('networkConfiguration').vmSubnet.name, 'addressPrefix', variables('networkConfiguration').vmSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('machineNetworkSecurityGroup').outputs.resourceId.value, null()))).pods), createArray()), if(parameters('enableBastion'), array(createObject('cluster', createObject('name', variables('networkConfiguration').aksSubnet.name, 'addressPrefix', variables('networkConfiguration').aksSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', variables('networkConfiguration').podSubnet.name, 'addressPrefix', variables('networkConfiguration').podSubnet.prefix, 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', variables('networkConfiguration').bastionSubnet.name, 'addressPrefix', variables('networkConfiguration').bastionSubnet.prefix, 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('bastionNetworkSecurityGroup').outputs.resourceId.value, null())), 'machine', createObject('name', variables('networkConfiguration').vmSubnet.name, 'addressPrefix', variables('networkConfiguration').vmSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('machineNetworkSecurityGroup').outputs.resourceId.value, null()))).bastion), createArray()), if(parameters('enableBastion'), array(createObject('cluster', createObject('name', variables('networkConfiguration').aksSubnet.name, 'addressPrefix', variables('networkConfiguration').aksSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'pods', createObject('name', variables('networkConfiguration').podSubnet.name, 'addressPrefix', variables('networkConfiguration').podSubnet.prefix, 'networkSecurityGroupResourceId', if(not(parameters('enableVnetInjection')), reference('clusterNetworkSecurityGroup').outputs.resourceId.value, null()), 'roleAssignments', createArray(createObject('roleDefinitionIdOrName', 'Network Contributor', 'principalId', parameters('identityId'), 'principalType', 'ServicePrincipal'))), 'bastion', createObject('name', variables('networkConfiguration').bastionSubnet.name, 'addressPrefix', variables('networkConfiguration').bastionSubnet.prefix, 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('bastionNetworkSecurityGroup').outputs.resourceId.value, null())), 'machine', createObject('name', variables('networkConfiguration').vmSubnet.name, 'addressPrefix', variables('networkConfiguration').vmSubnet.prefix, 'serviceEndpoints', createArray(createObject('service', 'Microsoft.Storage'), createObject('service', 'Microsoft.KeyVault'), createObject('service', 'Microsoft.ContainerRegistry')), 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroupResourceId', if(parameters('enableBastion'), reference('machineNetworkSecurityGroup').outputs.resourceId.value, null()))).machine), 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.21.1.54444", + "templateHash": "7839005038128499146" + }, + "name": "Virtual Networks", + "description": "This module deploys a Virtual Network (vNet).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", "properties": { - "category": { + "name": { "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." + "description": "Optional. Specify the name of lock." } }, - "categoryGroup": { + "kind": { "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], "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." + "description": "Optional. Specify the type of lock." } } - } + }, + "nullable": 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." + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "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 }, - "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." + "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." + } + } + } + }, + "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." + } + } + } + }, + "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 } }, - "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." + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The Virtual Network (vNet) Name." + } + }, + "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." + } + }, + "subnets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An Array of subnets to deploy to the Virtual Network." + } + }, + "dnsServers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. DNS Servers associated to the Virtual Network." + } + }, + "ddosProtectionPlanResourceId": { + "type": "string", + "defaultValue": "", + "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": [], + "metadata": { + "description": "Optional. Virtual Network Peerings 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 assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "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." + } } }, - "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 Virtual Network (vNet) Name." - } - }, - "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." - } - }, - "subnets": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." - } - }, - "ddosProtectionPlanResourceId": { - "type": "string", - "defaultValue": "", - "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": [], - "metadata": { - "description": "Optional. Virtual Network Peerings 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 assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - }, - "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": { - "dnsServersVar": { - "dnsServers": "[array(parameters('dnsServers'))]" - }, - "ddosProtectionPlan": { - "id": "[parameters('ddosProtectionPlanResourceId')]" - }, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{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" + "variables": { + "dnsServersVar": { + "dnsServers": "[array(parameters('dnsServers'))]" + }, + "ddosProtectionPlan": { + "id": "[parameters('ddosProtectionPlanResourceId')]" + }, + "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')]" } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2023-04-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]", + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "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(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", - "networkSecurityGroup": "[if(contains(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(contains(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')]" - }, - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), variables('ddosProtectionPlan'), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), variables('dnsServersVar'), 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())]" - } - }, - "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": { - "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')]", - "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", - "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(parameters('roleAssignments'), 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)]", - "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')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_subnets": { - "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(parameters('subnets'))]" - }, - "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": "[parameters('subnets')[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()))]" - }, - "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.21.1.54444", - "templateHash": "16295395838729593723" - }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." - } - }, - "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": "Optional. 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", - "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." + "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" + } + } + } } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." - } - } - }, - "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { "virtualNetwork": { - "existing": true, "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2023-04-01", - "name": "[parameters('virtualNetworkName')]" + "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(contains(parameters('subnets')[copyIndex('subnets')], 'natGatewayResourceId'), createObject('id', parameters('subnets')[copyIndex('subnets')].natGatewayResourceId), null())]", + "networkSecurityGroup": "[if(contains(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(contains(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')]" + }, + "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), variables('ddosProtectionPlan'), null())]", + "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), variables('dnsServersVar'), 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())]" + } }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", + "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": { - "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')]" + "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" ] }, - "subnet_roleAssignments": { + "virtualNetwork_diagnosticSettings": { "copy": { - "name": "subnet_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "name": "virtualNetwork_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), 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)]", - "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)]", + "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": { + "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')]", + "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "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(parameters('roleAssignments'), 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)]", + "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')]", @@ -5911,414 +5499,736 @@ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" }, "dependsOn": [ - "subnet" + "virtualNetwork" ] - } - }, - "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." + "virtualNetwork_subnets": { + "copy": { + "name": "virtualNetwork_subnets", + "count": "[length(parameters('subnets'))]" }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" - }, - "subnetAddressPrefix": { - "type": "string", - "metadata": { - "description": "The address prefix for the subnet." + "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": "[parameters('subnets')[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()))]" + }, + "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.21.1.54444", + "templateHash": "16295395838729593723" + }, + "name": "Virtual Network Subnets", + "description": "This module deploys a Virtual Network Subnet.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "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": "Optional. 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", + "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 assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "virtualNetwork": { + "existing": true, + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2023-04-01", + "name": "[parameters('virtualNetworkName')]" + }, + "subnet": { + "type": "Microsoft.Network/virtualNetworks/subnets", + "apiVersion": "2023-04-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(parameters('roleAssignments'), 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)]", + "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')]" + }, + "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'))]" + }, + "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())]" + } + } + } }, - "value": "[reference('subnet').addressPrefix]" + "dependsOn": [ + "virtualNetwork" + ] }, - "subnetAddressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." + "virtualNetwork_peering_local": { + "copy": { + "name": "virtualNetwork_peering_local", + "count": "[length(parameters('peerings'))]" }, - "value": "[if(not(empty(parameters('addressPrefixes'))), reference('subnet').addressPrefixes, createArray())]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_peering_local": { - "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(parameters('peerings'))]" - }, - "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')]" - }, - "remoteVirtualNetworkId": { - "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" - }, - "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()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "10220824930947117349" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", - "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." - } - }, - "remoteVirtualNetworkId": { - "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." - } + "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')]" + }, + "remoteVirtualNetworkId": { + "value": "[parameters('peerings')[copyIndex()].remoteVirtualNetworkId]" + }, + "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()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "10220824930947117349" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + } + }, + "remoteVirtualNetworkId": { + "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": "2023-04-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('remoteVirtualNetworkId')]" + } + } + } + ], + "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" + ] }, - "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": "2023-04-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", + "virtualNetwork_peering_remote": { + "copy": { + "name": "virtualNetwork_peering_remote", + "count": "[length(parameters('peerings'))]" + }, + "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), 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]]", "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localVnetName": { + "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" + }, + "remoteVirtualNetworkId": { + "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()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.21.1.54444", + "templateHash": "10220824930947117349" + }, + "name": "Virtual Network Peerings", + "description": "This module deploys a Virtual Network Peering.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", + "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." + } + }, + "remoteVirtualNetworkId": { + "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": "2023-04-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('remoteVirtualNetworkId')]" + } + } + } + ], + "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 peering was deployed into." + "description": "The resource group the virtual network 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." + "description": "The resource ID of the virtual network." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_peering_remote": { - "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(parameters('peerings'))]" - }, - "condition": "[if(contains(parameters('peerings')[copyIndex()], 'remotePeeringEnabled'), equals(parameters('peerings')[copyIndex()].remotePeeringEnabled, true()), 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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[last(split(parameters('peerings')[copyIndex()].remoteVirtualNetworkId, '/'))]" - }, - "remoteVirtualNetworkId": { - "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()))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.21.1.54444", - "templateHash": "10220824930947117349" + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering.", - "owner": "Azure/module-maintainers" - }, - "parameters": { "name": { - "type": "string", - "defaultValue": "[format('{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkId'), '/')))]", - "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." - } + "description": "The name of the virtual network." + }, + "value": "[parameters('name')]" }, - "remoteVirtualNetworkId": { - "type": "string", + "subnetNames": { + "type": "array", "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." + "description": "The names of the deployed subnets." + }, + "copy": { + "count": "[length(parameters('subnets'))]", + "input": "[parameters('subnets')[copyIndex()].name]" } }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, + "subnetResourceIds": { + "type": "array", "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." + "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)]" } }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, + "location": { + "type": "string", "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": "2023-04-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('remoteVirtualNetworkId')]" - } - } - } - ], - "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." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" + "value": "[reference('virtualNetwork', '2023-04-01', 'full').location]" } } } }, "dependsOn": [ - "virtualNetwork" + "bastionNetworkSecurityGroup", + "clusterNetworkSecurityGroup", + "machineNetworkSecurityGroup" ] } }, "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" + "networkConfiguration": { + "type": "object", + "value": "[variables('networkConfiguration')]" }, - "resourceId": { + "vnetId": { "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + "value": "[if(parameters('enableVnetInjection'), resourceId(variables('networkConfiguration').group, 'Microsoft.Network/virtualNetworks', variables('networkConfiguration').name), reference('network').outputs.resourceId.value)]" }, - "name": { + "aksSubnetId": { "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" + "value": "[if(parameters('enableVnetInjection'), format('{0}/subnets/{1}', resourceId(variables('networkConfiguration').group, 'Microsoft.Network/virtualNetworks', variables('networkConfiguration').name), variables('networkConfiguration').aksSubnet.name), format('{0}/subnets/{1}', reference('network').outputs.resourceId.value, variables('networkConfiguration').aksSubnet.name))]" }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(parameters('subnets'))]", - "input": "[parameters('subnets')[copyIndex()].name]" - } - }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "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)]" - } + "vmSubnetId": { + "type": "string", + "value": "[if(parameters('enableVnetInjection'), format('{0}/subnets/{1}', resourceId(variables('networkConfiguration').group, 'Microsoft.Network/virtualNetworks', variables('networkConfiguration').name), variables('networkConfiguration').vmSubnet.name), format('{0}/subnets/{1}', reference('network').outputs.resourceId.value, variables('networkConfiguration').vmSubnet.name))]" }, - "location": { + "podSubnetId": { "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetwork', '2023-04-01', 'full').location]" + "value": "[if(parameters('enableVnetInjection'), format('{0}/subnets/{1}', resourceId(variables('networkConfiguration').group, 'Microsoft.Network/virtualNetworks', variables('networkConfiguration').name), variables('networkConfiguration').podSubnet.name), format('{0}/subnets/{1}', reference('network').outputs.resourceId.value, variables('networkConfiguration').podSubnet.name))]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-bastion', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-cluster', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-network-security-group-manage', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" + "logAnalytics", + "stampIdentity" ] }, - { - "condition": "[parameters('enableVpnGateway')]", + "commonBlade": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-vpn-site', variables('commonLayerConfig').name)]", + "name": "common-blade", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[format('vpn-site-common{0}', uniqueString(resourceGroup().id, 'common'))]" + "bladeConfig": { + "value": { + "sectionName": "commonblade", + "displayName": "Common Resources" + } }, "location": { "value": "[parameters('location')]" @@ -6326,21 +6236,52 @@ "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } + "deploymentScriptIdentity": { + "value": "[reference('stampIdentity').outputs.name.value]" }, - "virtualWanId": { - "value": "[resourceId('Microsoft.Network/virtualWans', format('wan-common{0}', uniqueString(resourceGroup().id, 'common')))]" + "workspaceResourceId": { + "value": "[reference('logAnalytics').outputs.resourceId.value]" }, - "addressPrefixes": { + "workspaceName": { + "value": "[reference('logAnalytics').outputs.name.value]" + }, + "subnetId": { + "value": "[reference('networkBlade').outputs.aksSubnetId.value]" + }, + "cmekConfiguration": { + "value": "[parameters('cmekConfiguration')]" + }, + "enablePrivateLink": { + "value": "[parameters('enablePrivateLink')]" + }, + "enableBlobPublicAccess": { + "value": "[parameters('enableBlobPublicAccess')]" + }, + "workspaceIdName": { + "value": "[variables('configuration').secrets.logAnalyticsId]" + }, + "workspaceKeySecretName": { + "value": "[variables('configuration').secrets.logAnalyticsKey]" + }, + "vaultSecrets": { "value": [ - "[parameters('remoteNetworkPrefix')]" + { + "secretName": "[variables('configuration').secrets.tenantId]", + "secretValue": "[subscription().tenantId]" + }, + { + "secretName": "[variables('configuration').secrets.subscriptionId]", + "secretValue": "[subscription().subscriptionId]" + }, + { + "secretName": "[variables('configuration').secrets.clientId]", + "secretValue": "[parameters('applicationClientId')]" + }, + { + "secretName": "[variables('configuration').secrets.applicationPrincipalId]", + "secretValue": "[parameters('applicationClientId')]" + } ] - }, - "ipAddress": { - "value": "[parameters('remoteVpnAddress')]" } }, "template": { @@ -6350,5392 +6291,3862 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "1751598884441695432" - }, - "name": "VPN Sites", - "description": "This module deploys a VPN Site.", - "owner": "Azure/module-maintainers" + "version": "0.25.53.49325", + "templateHash": "13842981590527036962" + } }, "definitions": { - "lockType": { + "bladeSettings": { "type": "object", "properties": { - "name": { + "sectionName": { "type": "string", - "nullable": true, "metadata": { - "description": "Optional. Specify the name of lock." + "description": "The name of the section name" } }, - "kind": { + "displayName": { "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." - } + "description": "The display name of the section" } } - }, - "nullable": true + } } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the VPN Site." - } - }, - "virtualWanId": { - "type": "string", + "enableBlobPublicAccess": { + "type": "bool", "metadata": { - "description": "Required. Resource ID of the virtual WAN to link to." + "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." } }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Location where all resources will be created." + "description": "The location of resources to deploy" } }, - "tags": { - "type": "object", - "nullable": true, + "enableTelemetry": { + "type": "bool", "metadata": { - "description": "Optional. Tags of the resource." + "description": "Feature Flag to Enable Telemetry" } }, - "addressPrefixes": { - "type": "array", - "defaultValue": [], + "bladeConfig": { + "$ref": "#/definitions/bladeSettings", "metadata": { - "description": "Conditional. An array of IP address ranges that can be used by subnets of the virtual network. Required if no bgpProperties or VPNSiteLinks are configured." + "description": "The configuration for the blade section." } }, - "bgpProperties": { - "type": "object", - "defaultValue": {}, + "enablePrivateLink": { + "type": "bool", "metadata": { - "description": "Conditional. BGP settings details. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead. Required if no addressPrefixes or VPNSiteLinks are configured." + "description": "Feature Flag to Enable Private Link" } }, - "deviceProperties": { - "type": "object", - "defaultValue": {}, + "vaultSecrets": { + "type": "array", "metadata": { - "description": "Optional. List of properties of the device." + "description": "The list of secrets to persist to the Key Vault" } }, - "ipAddress": { + "workspaceResourceId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The IP-address for the VPN-site. Note: This is a deprecated property, please use the corresponding VpnSiteLinks property instead." + "description": "The workspace resource Id for diagnostics" } }, - "isSecuritySite": { - "type": "bool", - "defaultValue": false, + "workspaceName": { + "type": "string", "metadata": { - "description": "Optional. IsSecuritySite flag." + "description": "The Diagnostics Workspace Name" } }, - "o365Policy": { - "type": "object", - "defaultValue": {}, + "workspaceIdName": { + "type": "string", "metadata": { - "description": "Optional. The Office365 breakout policy." + "description": "The KeyVault Secret Name for the Workspace Id" } }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, + "workspaceKeySecretName": { + "type": "string", "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + "description": "The KeyVault Secret Name for the Workspace Key" } }, - "vpnSiteLinks": { - "type": "array", - "defaultValue": [], + "deploymentScriptIdentity": { + "type": "string", "metadata": { - "description": "Optional. List of all VPN site links." + "description": "The managed identity name for deployment scripts" } }, - "lock": { - "$ref": "#/definitions/lockType", + "subnetId": { + "type": "string", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "The subnet id for Private Endpoints" } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "cmekConfiguration": { + "type": "object", + "defaultValue": { + "kvUrl": "", + "keyName": "", + "identityId": "" + }, "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Optional. Customer Managed Encryption Key." } } }, "variables": { - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } + "commonLayerConfig": { + "secrets": { + "tenantId": "tenant-id", + "subscriptionId": "subscription-id", + "registryName": "container-registry", + "applicationId": "aad-client-id", + "clientId": "app-dev-sp-username", + "clientSecret": "app-dev-sp-password", + "applicationPrincipalId": "app-dev-sp-id", + "stampIdentity": "osdu-identity-id", + "storageAccountName": "common-storage", + "storageAccountKey": "common-storage-key", + "cosmosConnectionString": "graph-db-connection", + "cosmosEndpoint": "graph-db-endpoint", + "cosmosPrimaryKey": "graph-db-primary-key", + "logAnalyticsId": "log-workspace-id", + "logAnalyticsKey": "log-workspace-key" + }, + "storage": { + "sku": "Standard_LRS", + "tables": [ + "partitionInfo" + ], + "shares": [ + "crs", + "crs-conversion", + "unit", + "sample-share" + ] + }, + "database": { + "name": "graph-db", + "throughput": 2000, + "backup": "Continuous", + "graphs": [ + { + "name": "Entitlements", + "automaticIndexing": true, + "partitionKeyPaths": [ + "/dataPartitionId" + ] + } + ] + } + }, + "name": "[format('kv-{0}{1}', replace(parameters('bladeConfig').sectionName, '-', ''), uniqueString(resourceGroup().id, parameters('bladeConfig').sectionName))]", + "storageDNSZoneForwarder": "[format('blob.{0}', environment().suffixes.storage)]", + "storageDnsZoneName": "[format('privatelink.{0}', variables('storageDNSZoneForwarder'))]", + "cosmosDnsZoneName": "privatelink.documents.azure.com" }, "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-vpnsite.{0}.{1}', replace('0.1.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" - } - } - } - } - }, - "vpnSite": { - "type": "Microsoft.Network/vpnSites", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "addressSpace": "[if(not(empty(parameters('addressPrefixes'))), createObject('addressPrefixes', parameters('addressPrefixes')), null())]", - "bgpProperties": "[if(not(empty(parameters('bgpProperties'))), parameters('bgpProperties'), null())]", - "deviceProperties": "[if(not(empty(parameters('deviceProperties'))), parameters('deviceProperties'), null())]", - "ipAddress": "[if(not(empty(parameters('ipAddress'))), parameters('ipAddress'), null())]", - "isSecuritySite": "[parameters('isSecuritySite')]", - "o365Policy": "[if(not(empty(parameters('o365Policy'))), parameters('o365Policy'), null())]", - "virtualWan": { - "id": "[parameters('virtualWanId')]" - }, - "vpnSiteLinks": "[if(not(empty(parameters('vpnSiteLinks'))), parameters('vpnSiteLinks'), null())]" - } - }, - "vpnSite_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/vpnSites/{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": [ - "vpnSite" - ] - }, - "vpnSite_roleAssignments": { - "copy": { - "name": "vpnSite_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/vpnSites/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/vpnSites', 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": [ - "vpnSite" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VPN site." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VPN site." - }, - "value": "[resourceId('Microsoft.Network/vpnSites', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the VPN site was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vpnSite', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/virtualWans', format('wan-common{0}', uniqueString(resourceGroup().id, 'common')))]" - ] - }, - { - "condition": "[parameters('enableVpnGateway')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-vpn-gateway', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('vpn-gw-common{0}', uniqueString(resourceGroup().id, 'common'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "virtualHubResourceId": { - "value": "[resourceId('Microsoft.Network/virtualHubs', format('hub-common{0}', uniqueString(resourceGroup().id, 'common')))]" - }, - "vpnConnections": { - "value": [ - { - "name": "[format('vpn-connect-common{0}', uniqueString(resourceGroup().id, 'common'))]", - "connectionBandwidth": 100, - "enableBgp": false, - "enableInternetSecurity": true, - "enableRateLimiting": false, - "sharedKey": "[parameters('vpnSharedKey')]", - "remoteVpnSiteResourceId": "[if(parameters('enableVpnGateway'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-vpn-site', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null())]", - "routingWeight": 0, - "useLocalAzureIpAddress": false, - "usePolicyBasedTrafficSelectors": false, - "vpnConnectionProtocolType": "IKEv2" - } - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "7269875381422514128" - }, - "name": "VPN Gateways", - "description": "This module deploys a VPN 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 - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the VPN gateway." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location where all resources will be created." - } - }, - "vpnConnections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The VPN connections to create in the VPN gateway." - } - }, - "natRules": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of all the NAT Rules to associate with the gateway." - } - }, - "virtualHubResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a virtual Hub to connect to. Note: The virtual Hub and Gateway must be deployed into the same location." - } - }, - "bgpSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. BGP settings details." - } - }, - "enableBgpRouteTranslationForNat": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable BGP routes translation for NAT on this VPN gateway." - } - }, - "isRoutingPreferenceInternet": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable routing preference property for the public IP interface of the VPN gateway." - } - }, - "vpnGatewayScaleUnit": { - "type": "int", - "defaultValue": 2, - "metadata": { - "description": "Optional. The scale unit for this VPN gateway." - } + "vaultDNSZone": { + "condition": "[parameters('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "privatelink.vaultcore.azure.net", + "location": "global", + "properties": {} }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } + "storageDNSZone": { + "condition": "[parameters('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('storageDnsZoneName')]", + "location": "global", + "properties": {} }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } + "cosmosDNSZone": { + "condition": "[parameters('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('cosmosDnsZoneName')]", + "location": "global", + "properties": {} }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "keyvault": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[take(format('46d3xbcp.res.network-vpngateway.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4)), 64)]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', parameters('bladeConfig').sectionName)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": "[if(greater(length(variables('name')), 24), createObject('value', substring(variables('name'), 0, 24)), createObject('value', variables('name')))]", + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } + }, + "enablePurgeProtection": { + "value": false + }, + "enableRbacAuthorization": { + "value": true + }, + "secrets": { + "value": { + "copy": [ + { + "name": "secureList", + "count": "[length(parameters('vaultSecrets'))]", + "input": { + "name": "[parameters('vaultSecrets')[copyIndex('secureList')].secretName]", + "value": "[parameters('vaultSecrets')[copyIndex('secureList')].secretValue]" + } + } + ] + } + } + }, "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" - } - } - } - } - }, - "vpnGateway": { - "type": "Microsoft.Network/vpnGateways", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "connections", - "count": "[length(parameters('vpnConnections'))]", - "input": { - "name": "[parameters('vpnConnections')[copyIndex('connections')].name]", - "properties": { - "connectionBandwidth": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'connectionBandwidth')]", - "enableBgp": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'enableBgp')]", - "enableInternetSecurity": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'enableInternetSecurity')]", - "remoteVpnSite": "[if(contains(parameters('vpnConnections')[copyIndex('connections')], 'remoteVpnSiteResourceId'), createObject('id', parameters('vpnConnections')[copyIndex('connections')].remoteVpnSiteResourceId), null())]", - "enableRateLimiting": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'enableRateLimiting')]", - "routingConfiguration": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'routingConfiguration')]", - "routingWeight": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'routingWeight')]", - "sharedKey": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'sharedKey')]", - "useLocalAzureIpAddress": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'useLocalAzureIpAddress')]", - "usePolicyBasedTrafficSelectors": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'usePolicyBasedTrafficSelectors')]", - "vpnConnectionProtocolType": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'vpnConnectionProtocolType')]", - "ipsecPolicies": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'ipsecPolicies')]", - "trafficSelectorPolicies": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'trafficSelectorPolicies')]", - "vpnLinkConnections": "[tryGet(parameters('vpnConnections')[copyIndex('connections')], 'vpnLinkConnections')]" - } - } - } - ], - "bgpSettings": "[parameters('bgpSettings')]", - "enableBgpRouteTranslationForNat": "[parameters('enableBgpRouteTranslationForNat')]", - "isRoutingPreferenceInternet": "[parameters('isRoutingPreferenceInternet')]", - "vpnGatewayScaleUnit": "[parameters('vpnGatewayScaleUnit')]", - "virtualHub": { - "id": "[parameters('virtualHubResourceId')]" - } - } - }, - "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/vpnGateways/{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": [ - "vpnGateway" - ] - }, - "vpnGateway_natRules": { - "copy": { - "name": "vpnGateway_natRules", - "count": "[length(parameters('natRules'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NATRule-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('natRules')[copyIndex()].name]" - }, - "vpnGatewayName": { - "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', ''))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "6015512722948676501" + "version": "0.24.24.22086", + "templateHash": "15629192251973726626" }, - "name": "VPN Gateway NAT Rules", - "description": "This module deploys a VPN Gateway NAT Rule.", + "name": "Key Vaults", + "description": "This module deploys a Key Vault.", "owner": "Azure/module-maintainers" }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the NAT rule." - } - }, - "vpnGatewayName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent VPN gateway this NAT rule is associated with. Required if the template is used in a standalone deployment." - } - }, - "externalMappings": { + "definitions": { + "diagnosticSettingType": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An address prefix range of destination IPs on the outside network that source IPs will be mapped to. In other words, your post-NAT address prefix range." - } + "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." + } + } + } + }, + "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." + } + } + } + }, + "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 }, - "internalMappings": { + "roleAssignmentType": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An address prefix range of source IPs on the inside network that will be mapped to a set of external IPs. In other words, your pre-NAT address prefix range." - } - }, - "ipConfigurationId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. A NAT rule must be configured to a specific VPN Gateway instance. This is applicable to Dynamic NAT only. Static NAT rules are automatically applied to both VPN Gateway instances." - } - }, - "mode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "EgressSnat", - "IngressSnat" - ], - "metadata": { - "description": "Optional. The type of NAT rule for VPN NAT. IngressSnat mode (also known as Ingress Source NAT) is applicable to traffic entering the Azure hub's site-to-site VPN gateway. EgressSnat mode (also known as Egress Source NAT) is applicable to traffic leaving the Azure hub's Site-to-site VPN gateway." - } + "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 }, - "type": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The type of NAT rule for VPN NAT. Static one-to-one NAT establishes a one-to-one relationship between an internal address and an external address while Dynamic NAT assigns an IP and port based on availability." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/vpnGateways/natRules", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('vpnGatewayName'), parameters('name'))]", - "properties": { - "externalMappings": "[parameters('externalMappings')]", - "internalMappings": "[parameters('internalMappings')]", - "ipConfigurationId": "[if(not(empty(parameters('ipConfigurationId'))), parameters('ipConfigurationId'), null())]", - "mode": "[if(not(empty(parameters('mode'))), parameters('mode'), null())]", - "type": "[if(not(empty(parameters('type'))), parameters('type'), null())]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the NAT rule." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the NAT rule." + "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", + "nullable": true, + "metadata": { + "description": "Optional. 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." + } + }, + "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." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } }, - "value": "[resourceId('Microsoft.Network/vpnGateways/natRules', parameters('vpnGatewayName'), parameters('name'))]" + "nullable": true }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the NAT rule was deployed into." + "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." + } + } }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "vpnGateway" - ] - }, - "vpnGateway_vpnConnections": { - "copy": { - "name": "vpnGateway_vpnConnections", - "count": "[length(parameters('vpnConnections'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Connection-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('vpnConnections')[copyIndex()].name]" - }, - "vpnGatewayName": { - "value": "[parameters('name')]" - }, - "connectionBandwidth": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'connectionBandwidth')]" - }, - "enableBgp": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'enableBgp')]" - }, - "enableInternetSecurity": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'enableInternetSecurity')]" - }, - "remoteVpnSiteResourceId": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'remoteVpnSiteResourceId')]" - }, - "enableRateLimiting": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'enableRateLimiting')]" - }, - "routingConfiguration": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'routingConfiguration')]" - }, - "routingWeight": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'routingWeight')]" - }, - "sharedKey": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'sharedKey')]" - }, - "useLocalAzureIpAddress": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'useLocalAzureIpAddress')]" - }, - "usePolicyBasedTrafficSelectors": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'usePolicyBasedTrafficSelectors')]" - }, - "vpnConnectionProtocolType": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'vpnConnectionProtocolType')]" - }, - "trafficSelectorPolicies": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'trafficSelectorPolicies')]" - }, - "vpnLinkConnections": { - "value": "[tryGet(parameters('vpnConnections')[copyIndex()], 'vpnLinkConnections')]" - } - }, - "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": "12494321080277868905" - }, - "name": "VPN Gateway VPN Connections", - "description": "This module deploys a VPN Gateway VPN Connection.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the VPN connection." - } - }, - "vpnGatewayName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent VPN gateway this VPN connection is associated with. Required if the template is used in a standalone deployment." - } - }, - "ipsecPolicies": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The IPSec policies to be considered by this connection." - } - }, - "trafficSelectorPolicies": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The traffic selector policies to be considered by this connection." - } + "nullable": true }, - "vpnLinkConnections": { + "accessPoliciesType": { "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of all VPN site link connections to the gateway." - } - }, - "routingConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Routing configuration indicating the associated and propagated route tables for this connection." - } - }, - "usePolicyBasedTrafficSelectors": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable policy-based traffic selectors." - } - }, - "useLocalAzureIpAddress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Use local Azure IP to initiate connection." - } - }, - "enableRateLimiting": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable rate limiting." - } - }, - "enableInternetSecurity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable internet security." - } - }, - "enableBgp": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enable BGP flag." - } - }, - "routingWeight": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Routing weight for VPN connection." + "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": { + "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": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "type": "array", + "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." } }, - "connectionBandwidth": { + "softDeleteRetentionInDays": { "type": "int", - "defaultValue": 10, + "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. Expected bandwidth in MBPS." + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." } }, - "vpnConnectionProtocolType": { + "sku": { "type": "string", - "defaultValue": "IKEv2", + "defaultValue": "premium", "allowedValues": [ - "IKEv1", - "IKEv2" + "premium", + "standard" ], "metadata": { - "description": "Optional. Gateway connection protocol." + "description": "Optional. Specifies the SKU for the vault." } }, - "sharedKey": { - "type": "securestring", - "defaultValue": "", + "networkAcls": { + "type": "object", + "nullable": true, "metadata": { - "description": "Optional. SharedKey for the VPN connection." + "description": "Optional. Rules governing the accessibility of the resouce from specific network locations." } }, - "remoteVpnSiteResourceId": { + "publicNetworkAccess": { "type": "string", "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], "metadata": { - "description": "Optional. Reference to a VPN site to link to." + "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." } - } - }, - "resources": [ - { - "type": "Microsoft.Network/vpnGateways/vpnConnections", - "apiVersion": "2023-04-01", - "name": "[format('{0}/{1}', parameters('vpnGatewayName'), parameters('name'))]", - "properties": { - "connectionBandwidth": "[parameters('connectionBandwidth')]", - "enableBgp": "[parameters('enableBgp')]", - "enableInternetSecurity": "[parameters('enableInternetSecurity')]", - "enableRateLimiting": "[parameters('enableRateLimiting')]", - "ipsecPolicies": "[parameters('ipsecPolicies')]", - "remoteVpnSite": "[if(not(empty(parameters('remoteVpnSiteResourceId'))), createObject('id', parameters('remoteVpnSiteResourceId')), null())]", - "routingConfiguration": "[parameters('routingConfiguration')]", - "routingWeight": "[parameters('routingWeight')]", - "sharedKey": "[parameters('sharedKey')]", - "trafficSelectorPolicies": "[parameters('trafficSelectorPolicies')]", - "useLocalAzureIpAddress": "[parameters('useLocalAzureIpAddress')]", - "usePolicyBasedTrafficSelectors": "[parameters('usePolicyBasedTrafficSelectors')]", - "vpnConnectionProtocolType": "[parameters('vpnConnectionProtocolType')]", - "vpnLinkConnections": "[parameters('vpnLinkConnections')]" + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." } - } - ], - "outputs": { - "name": { - "type": "string", + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", "metadata": { - "description": "The name of the VPN connection." - }, - "value": "[parameters('name')]" + "description": "Optional. Array of role assignments to create." + } }, - "resourceId": { - "type": "string", + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", "metadata": { - "description": "The resource ID of the VPN connection." - }, - "value": "[resourceId('Microsoft.Network/vpnGateways/vpnConnections', parameters('vpnGatewayName'), parameters('name'))]" + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } }, - "resourceGroupName": { - "type": "string", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "The name of the resource group the VPN connection was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "vpnGateway" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VPN gateway." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VPN gateway." - }, - "value": "[resourceId('Microsoft.Network/vpnGateways', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VPN gateway was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vpnGateway', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/virtualHubs', format('hub-common{0}', uniqueString(resourceGroup().id, 'common')))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-vpn-site', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-keyvault', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('kv-{0}{1}', replace(variables('commonLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('commonLayerConfig').name))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "enablePurgeProtection": { - "value": false - }, - "enableRbacAuthorization": { - "value": true - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Key Vault Reader", - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "secrets": { - "value": { - "copy": [ - { - "name": "secureList", - "count": "[length(variables('vaultSecrets'))]", - "input": { - "name": "[variables('vaultSecrets')[copyIndex('secureList')].secretName]", - "value": "[variables('vaultSecrets')[copyIndex('secureList')].secretValue]" - } - } - ] - } - } - }, - "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.24.24.22086", - "templateHash": "15629192251973726626" - }, - "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." + "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." + } } }, - "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." - } + "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)]" } } + ], + "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 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')]" }, - "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." - } + "secretList": "[coalesce(tryGet(parameters('secrets'), 'secureList'), createArray())]" }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.3.4', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "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." + "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" + } } } } }, - "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": { - "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." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. 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" + "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()))]" + } }, - "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." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", + "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": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Required. Fqdn that resolves to private endpoint IP address." - } + "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": { + "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')]", + "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults', 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": [ + "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" }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" + "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": { - "description": "Required. A list of private IP addresses of the private endpoint." + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "5144103047835198105" + }, + "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" + ] }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "type": "object", + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(variables('secretList'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('secretList')[copyIndex()].name]" + }, + "value": { + "value": "[variables('secretList')[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[coalesce(tryGet(variables('secretList')[copyIndex()], 'attributesEnabled'), true())]" + }, + "attributesExp": { + "value": "[tryGet(variables('secretList')[copyIndex()], 'attributesExp')]" + }, + "attributesNbf": { + "value": "[tryGet(variables('secretList')[copyIndex()], 'attributesNbf')]" + }, + "contentType": { + "value": "[tryGet(variables('secretList')[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(variables('secretList')[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(variables('secretList')[copyIndex()], 'roleAssignments')]" } }, - "properties": { - "type": "object", - "properties": { - "groupId": { + "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.24.24.22086", + "templateHash": "14698549572049105523" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "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": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." } }, - "memberName": { + "name": { "type": "string", "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + "description": "Required. The name of the secret." } }, - "privateIPAddress": { - "type": "string", + "tags": { + "type": "object", + "nullable": true, "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." + "description": "Optional. Resource tags." } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." + }, + "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": { + "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 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": { + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), 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": [ + "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]" + } } } - } - }, - "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." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - } - }, - "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." - } - } + "dependsOn": [ + "keyVault" + ] }, - "metadata": { - "description": "Required. Permissions the identity has for keys, secrets and certificates." - } - } - } - }, - "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": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. All secrets to create." - } - }, - "keys": { - "type": "array", - "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 resouce 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": "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 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')]" - }, - "secretList": "[coalesce(tryGet(parameters('secrets'), 'secureList'), createArray())]" - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.3.4', '.', '-'), 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": { - "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')]", - "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", - "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(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults', 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": [ - "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.24.24.22086", - "templateHash": "5144103047835198105" - }, - "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." - } + "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]" }, - "objectId": { - "type": "string", - "metadata": { - "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." - } + "keyVaultName": { + "value": "[parameters('name')]" }, - "applicationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Application ID of the client making request on behalf of a principal." - } + "attributesEnabled": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled'), true())]" }, - "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." + "attributesExp": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" + }, + "attributesNbf": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf')]" + }, + "curveName": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')]" + }, + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize')]" + }, + "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.24.24.22086", + "templateHash": "17466785154213688764" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "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." + } + } } }, - "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." - } + "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." } }, - "metadata": { - "description": "Required. Permissions the identity has for keys, secrets and certificates." + "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." + } + }, + "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": { + "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 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": { + "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": "[parameters('rotationPolicy')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), 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": [ + "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]" } } } }, - "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." + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, - "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" - } - } - } - }, - "dependsOn": [ - "keyVault" - ] - }, - "keyVault_secrets": { - "copy": { - "name": "keyVault_secrets", - "count": "[length(variables('secretList'))]" - }, - "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": "[variables('secretList')[copyIndex()].name]" - }, - "value": { - "value": "[variables('secretList')[copyIndex()].value]" - }, - "keyVaultName": { - "value": "[parameters('name')]" - }, - "attributesEnabled": { - "value": "[coalesce(tryGet(variables('secretList')[copyIndex()], 'attributesEnabled'), true())]" - }, - "attributesExp": { - "value": "[tryGet(variables('secretList')[copyIndex()], 'attributesExp')]" - }, - "attributesNbf": { - "value": "[tryGet(variables('secretList')[copyIndex()], 'attributesNbf')]" - }, - "contentType": { - "value": "[tryGet(variables('secretList')[copyIndex()], 'contentType')]" - }, - "tags": { - "value": "[coalesce(tryGet(variables('secretList')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "roleAssignments": { - "value": "[tryGet(variables('secretList')[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.24.24.22086", - "templateHash": "14698549572049105523" - }, - "name": "Key Vault Secrets", - "description": "This module deploys a Key Vault Secret.", - "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." + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateLinkServiceConnections": { + "value": [ + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')]" + ] + } + } + ] + }, + "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()))]" + }, + "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'))]" + }, + "manualPrivateLinkServiceConnections": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" + }, + "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.23.1.45101", + "templateHash": "2821141217598568122" + }, + "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 } }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." + "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." + } } }, - "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\"." + "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')]" } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" - ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.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.23.1.45101", + "templateHash": "18168683629401652671" + }, + "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" + ] } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "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]" } } } }, - "nullable": true + "dependsOn": [ + "keyVault" + ] } }, - "parameters": { - "keyVaultName": { + "outputs": { + "resourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } + "description": "The resource ID of the key vault." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" }, - "name": { + "resourceGroupName": { "type": "string", "metadata": { - "description": "Required. The name of the secret." - } + "description": "The name of the resource group the key vault was created in." + }, + "value": "[resourceGroup().name]" }, - "tags": { - "type": "object", - "nullable": true, + "name": { + "type": "string", "metadata": { - "description": "Optional. Resource tags." - } + "description": "The name of the key vault." + }, + "value": "[parameters('name')]" }, - "attributesEnabled": { - "type": "bool", - "defaultValue": true, + "uri": { + "type": "string", "metadata": { - "description": "Optional. Determines whether the object is enabled." - } + "description": "The URI of the key vault." + }, + "value": "[reference('keyVault').vaultUri]" }, - "attributesExp": { - "type": "int", - "nullable": true, + "location": { + "type": "string", "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, + "description": "The location the resource was deployed into." + }, + "value": "[reference('keyVault', '2022-07-01', 'full').location]" + } + } + } + } + }, + "keyvaultSecrets": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-diag-secrets', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[reference('keyvault').outputs.name.value]" + }, + "workspaceName": { + "value": "[parameters('workspaceName')]" + }, + "workspaceIdName": { + "value": "[parameters('workspaceIdName')]" + }, + "workspaceKeySecretName": { + "value": "[parameters('workspaceKeySecretName')]" + } + }, + "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": "5125843450726619793" + } + }, + "parameters": { + "keyVaultName": { + "type": "string", "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." } }, - "contentType": { - "type": "securestring", - "nullable": true, + "workspaceName": { + "type": "string", "metadata": { - "description": "Optional. The content type of the secret." + "description": "Conditional. The name of the Analytics Workspace. Required if the template is used in a standalone deployment." } }, - "value": { - "type": "securestring", + "workspaceIdName": { + "type": "string", "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." + "description": "Required. The name of the secret." } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "workspaceKeySecretName": { + "type": "string", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Required. The name of the secret." } } }, - "variables": { - "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 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": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secret": { + "resources": [ + { "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('workspaceKeySecretName'))]", "properties": { - "contentType": "[parameters('contentType')]", - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "value": "[parameters('value')]" - }, - "dependsOn": [ - "keyVault" - ] + "value": "[listKeys(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '2022-10-01').primarySharedKey]" + } }, - "secret_roleAssignments": { - "copy": { - "name": "secret_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('workspaceIdName'))]", "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": [ - "secret" - ] + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" + } } - }, + ], "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]" + "value": "[parameters('keyVaultName')]" } } } }, "dependsOn": [ - "keyVault" + "keyvault" ] }, - "keyVault_keys": { - "copy": { - "name": "keyVault_keys", - "count": "[length(coalesce(parameters('keys'), createArray()))]" - }, + "sshKey": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-keyvault-sshkey', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" - }, - "keyVaultName": { - "value": "[parameters('name')]" - }, - "attributesEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesEnabled'), true())]" + "kvName": { + "value": "[reference('keyvault').outputs.name.value]" }, - "attributesExp": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesExp')]" - }, - "attributesNbf": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributesNbf')]" - }, - "curveName": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')]" - }, - "keyOps": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + "location": { + "value": "[parameters('location')]" }, - "keySize": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize')]" + "useExistingManagedIdentity": { + "value": true }, - "kty": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + "managedIdentityName": { + "value": "[parameters('deploymentScriptIdentity')]" }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "existingManagedIdentitySubId": { + "value": "[subscription().subscriptionId]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + "existingManagedIdentityResourceGroupName": { + "value": "[resourceGroup().name]" }, - "rotationPolicy": { - "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + "sshKeyName": { + "value": "PrivateLinkSSHKey-" } }, "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.24.24.22086", - "templateHash": "17466785154213688764" + "version": "0.25.53.49325", + "templateHash": "6068416468572067048" }, - "name": "Key Vault Keys", - "description": "This module deploys a Key Vault Key.", - "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 - } + "name": "SSH Key Pair", + "description": "This module creates a SSH Key Pair and stores it in an Azure Key Vault", + "owner": "azure-global-energy" }, "parameters": { - "keyVaultName": { + "kvName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "The name of the Azure Key Vault" } }, - "name": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The name of the key." + "description": "The location of the Key Vault and where to deploy the module resources to" } }, - "tags": { - "type": "object", - "nullable": true, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", "metadata": { - "description": "Optional. Resource tags." + "description": "How the deployment script should be forced to execute" + } + }, + "rbacRoleNeeded": { + "type": "string", + "defaultValue": "b86a8fe4-44ce-4948-aee5-eccb2c155cd7", + "metadata": { + "description": "Azure RoleId that are required for the DeploymentScript resource to import images" } }, - "attributesEnabled": { + "useExistingManagedIdentity": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Optional. Determines whether the object is enabled." + "description": "Does the Managed Identity already exists, or should be created" } }, - "attributesExp": { - "type": "int", - "nullable": true, + "managedIdentityName": { + "type": "string", + "defaultValue": "[format('id-keyvault-ssh-{0}', parameters('location'))]", "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." + "description": "Name of the Managed Identity resource" } }, - "attributesNbf": { - "type": "int", - "nullable": true, + "existingManagedIdentitySubId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", "metadata": { - "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + "description": "For an existing Managed Identity, the Subscription Id it is located in" } }, - "curveName": { + "existingManagedIdentityResourceGroupName": { "type": "string", - "defaultValue": "P-256", - "allowedValues": [ - "P-256", - "P-256K", - "P-384", - "P-521" - ], + "defaultValue": "[resourceGroup().name]", "metadata": { - "description": "Optional. The elliptic curve name." + "description": "For an existing Managed Identity, the Resource Group it is located in" } }, - "keyOps": { - "type": "array", - "nullable": true, - "allowedValues": [ - "decrypt", - "encrypt", - "import", - "sign", - "unwrapKey", - "verify", - "wrapKey" - ], + "sshKeyName": { + "type": "string", "metadata": { - "description": "Optional. Array of JsonWebKeyOperation." + "description": "The name of the SSH Key to be created.\nif name is my-virtual-machine-ssh then the private key will be named my-virtual-machine-sshprivate and the public key will be named my-virtual-machine-sshpublic.\n" } }, - "keySize": { - "type": "int", - "nullable": true, + "initialScriptDelay": { + "type": "string", + "defaultValue": "30s", "metadata": { - "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" } }, - "kty": { + "cleanupPreference": { "type": "string", - "defaultValue": "EC", + "defaultValue": "OnSuccess", "allowedValues": [ - "EC", - "EC-HSM", - "RSA", - "RSA-HSM" + "OnSuccess", + "OnExpiration", + "Always" ], "metadata": { - "description": "Optional. The type of the key." - } - }, - "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." + "description": "When the script resource is cleaned up" } } }, "variables": { - "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 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')]" - } + "$fxv#0": "#!/bin/bash\nset -e\n\necho \"Waiting on Identity RBAC replication ($initialDelay)\"\nsleep $initialDelay\n\n# Generate the SSH key pair\necho \"Generating SSH key pair...\"\n#ssh-keygen -t rsa -b 4096 -C \"azure@example.com\" -f id_rsa -N \"\"\nssh-keygen -m PEM -t rsa -b 4096 -f id_rsa -q\n\n# Import the private key and public key as strings\nprivateKey=$(cat id_rsa)\npublicKey=$(cat id_rsa.pub)\n\n# Re-Login to Azure CLI using the managed identity\necho \"Logging in to Azure CLI using managed identity...\"\naz login --identity\n\necho \"Storing secret ${sshKeyName}private in Key Vault $keyVaultName...\"\nprivSecret=$(az keyvault secret set --vault-name \"$keyVaultName\" --name \"${sshKeyNamePrivate}\" --value \"$privateKey\")\n\necho \"Storing secret ${sshKeyName}public in Key Vault $keyVaultName...\"\npubSecret=$(az keyvault secret set --vault-name \"$keyVaultName\" --name \"${sshKeyNamePublic}\" --value \"$publicKey\")\n\nprivateSecretId=$(echo $privSecret | jq -r \".id\" | cut -d'/' -f-5) # remove the version from the url;\npublicSecretId=$(echo $pubSecret | jq -r \".id\" | cut -d'/' -f-5) # remove the version from the url;\n\njsonOutputString=$(jq -cn --arg public $publicSecretId --arg private $privateSecretId '{secretUris: $ARGS.named}')\necho $jsonOutputString\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH\n\n# Cleanup\nrm -f id_rsa id_rsa.pub", + "privateKeySecretName": "[format('{0}private', parameters('sshKeyName'))]", + "publicKeySecretName": "[format('{0}public', parameters('sshKeyName'))]" }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2022-07-01", - "name": "[parameters('keyVaultName')]" + "resources": [ + { + "condition": "[not(parameters('useExistingManagedIdentity'))]", + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('managedIdentityName')]", + "location": "[parameters('location')]" }, - "key": { - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "tags": "[parameters('tags')]", + { + "condition": "[not(empty(parameters('rbacRoleNeeded')))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRoleNeeded'), if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]", "properties": { - "attributes": { - "enabled": "[parameters('attributesEnabled')]", - "exp": "[parameters('attributesExp')]", - "nbf": "[parameters('attributesNbf')]" - }, - "curveName": "[parameters('curveName')]", - "keyOps": "[parameters('keyOps')]", - "keySize": "[parameters('keySize')]", - "kty": "[parameters('kty')]", - "rotationPolicy": "[parameters('rotationPolicy')]" + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRoleNeeded'))]", + "principalId": "[if(parameters('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId)]", + "principalType": "ServicePrincipal" }, "dependsOn": [ - "keyVault" + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" ] }, - "key_roleAssignments": { - "copy": { - "name": "key_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2020-10-01", + "name": "[format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('sshKeyName'), ':', ''), '/', '-'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} + } }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "kind": "AzureCLI", "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')]" + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "azCliVersion": "2.45.0", + "timeout": "PT15M", + "retentionInterval": "PT1H", + "environmentVariables": [ + { + "name": "keyVaultName", + "value": "[parameters('kvName')]" + }, + { + "name": "sshKeyNamePrivate", + "value": "[variables('privateKeySecretName')]" + }, + { + "name": "sshKeyNamePublic", + "value": "[variables('publicKeySecretName')]" + }, + { + "name": "initialDelay", + "value": "[parameters('initialScriptDelay')]" + } + ], + "scriptContent": "[variables('$fxv#0')]", + "cleanupPreference": "[parameters('cleanupPreference')]" }, "dependsOn": [ - "key" + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", + "[extensionResourceId(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRoleNeeded'), if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))))]" ] } - }, + ], "outputs": { - "name": { + "publicKeyUri": { "type": "string", "metadata": { - "description": "The name of the key." + "description": "The URI of the public key secret in the Key Vault" }, - "value": "[parameters('name')]" + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('sshKeyName'), ':', ''), '/', '-'))), '2020-10-01').outputs.secretUris.public]" }, - "resourceId": { + "privateKeyUri": { "type": "string", "metadata": { - "description": "The resource ID of the key." + "description": "The URI of the private key secret in the Key Vault" }, - "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('sshKeyName'), ':', ''), '/', '-'))), '2020-10-01').outputs.secretUris.private]" }, - "resourceGroupName": { + "publicKeySecretName": { "type": "string", "metadata": { - "description": "The name of the resource group the key was created in." + "description": "The name of the public key secret in the Key Vault" }, - "value": "[resourceGroup().name]" + "value": "[variables('publicKeySecretName')]" + }, + "privateKeySecretName": { + "type": "string", + "metadata": { + "description": "The name of the private key secret in the Key Vault" + }, + "value": "[variables('privateKeySecretName')]" } } } }, "dependsOn": [ - "keyVault" + "keyvault" ] }, - "keyVault_privateEndpoints": { - "copy": { - "name": "keyVault_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, + "certificates": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-KeyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-keyvault-cert', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "privateLinkServiceConnections": { - "value": [ - { - "name": "[parameters('name')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]", - "groupIds": [ - "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')]" - ] - } - } - ] - }, - "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()))]" - }, - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + "kvName": { + "value": "[reference('keyvault').outputs.name.value]" }, "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')]" + "value": "[parameters('location')]" }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + "useExistingManagedIdentity": { + "value": true }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + "managedIdentityName": { + "value": "[parameters('deploymentScriptIdentity')]" }, - "manualPrivateLinkServiceConnections": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" + "existingManagedIdentitySubId": { + "value": "[subscription().subscriptionId]" }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + "existingManagedIdentityResourceGroupName": { + "value": "[resourceGroup().name]" }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + "certificateNames": { + "value": [ + "https-certificate" + ] }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + "initialScriptDelay": { + "value": "0" }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + "validity": { + "value": 24 } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "2821141217598568122" + "version": "0.25.53.49325", + "templateHash": "6320470553017221975" }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint.", - "owner": "Azure/module-maintainers" + "name": "Key Vault Certificate", + "description": "This module creates a Key Vault Certificate and stores it in an Azure Key Vault", + "owner": "azure-global-energy" }, - "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": { + "kvName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Key Vault" + } }, - "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 + "location": { + "type": "string", + "metadata": { + "description": "The location to deploy the resources to" + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "How the deployment script should be forced to execute" + } + }, + "rbacRolesNeededOnKV": { + "type": "string", + "defaultValue": "a4417e6f-fecd-4de8-b567-7b0420556985", + "metadata": { + "description": "The RoleDefinitionId required for the DeploymentScript resource to interact with KeyVault" + } + }, + "useExistingManagedIdentity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Does the Managed Identity already exists, or should be created" + } + }, + "managedIdentityName": { + "type": "string", + "defaultValue": "[format('id-KeyVaultCertificateCreator-{0}', parameters('location'))]", + "metadata": { + "description": "Name of the Managed Identity resource" + } + }, + "existingManagedIdentitySubId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "For an existing Managed Identity, the Subscription Id it is located in" + } + }, + "existingManagedIdentityResourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "For an existing Managed Identity, the Resource Group it is located in" + } }, - "ipConfigurationsType": { + "certificateNames": { "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": "The names of the certificate to create. Use when creating many certificates." + } }, - "manualPrivateLinkServiceConnectionsType": { + "certificateCommonNames": { "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", + "defaultValue": "[parameters('certificateNames')]", "metadata": { - "description": "Required. Name of the private endpoint resource to create." + "description": "The common names of the certificate to create. Use when creating many certificates." } }, - "subnetResourceId": { + "initialScriptDelay": { "type": "string", + "defaultValue": "0", "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." + "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" } }, - "customNetworkInterfaceName": { + "cleanupPreference": { "type": "string", - "nullable": true, + "defaultValue": "OnSuccess", + "allowedValues": [ + "OnSuccess", + "OnExpiration", + "Always" + ], "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." + "description": "When the script resource is cleaned up" } }, - "ipConfigurations": { - "$ref": "#/definitions/ipConfigurationsType", + "issuerName": { + "type": "string", + "defaultValue": "Self", "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + "description": "Self, or user defined {IssuerName} for certificate signing" } }, - "privateDnsZoneGroupName": { + "issuerProvider": { "type": "string", - "nullable": true, + "defaultValue": "", "metadata": { - "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + "description": "Certificate Issuer Provider, DigiCert, GlobalSign, or internal options may be used." } }, - "privateDnsZoneResourceIds": { - "type": "array", - "nullable": true, + "disabled": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + "description": "Create certificate in disabled state. Default: false" } }, - "location": { + "accountId": { "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "lock": { - "$ref": "#/definitions/lockType", + "defaultValue": "", "metadata": { - "description": "Optional. The lock settings of the service." + "description": "Account ID of Certificate Issuer Account" } }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", + "issuerPassword": { + "type": "securestring", + "defaultValue": "", "metadata": { - "description": "Optional. Array of role assignments to create." + "description": "Password of Certificate Issuer Account" } }, - "tags": { - "type": "object", - "nullable": true, + "organizationId": { + "type": "string", + "defaultValue": "", "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + "description": "Organization ID of Certificate Issuer Account" } }, - "customDnsConfigs": { - "$ref": "#/definitions/customDnsConfigType", + "isCrossTenant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. Custom DNS configurations." + "description": "Override this parameter if using this in cross tenant scenarios" } }, - "manualPrivateLinkServiceConnections": { - "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "reuseKey": { + "type": "bool", + "defaultValue": true, "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." + "description": "The default policy might cause errors about CSR being used before, so set this to false if that happens" } }, - "privateLinkServiceConnections": { - "$ref": "#/definitions/privateLinkServiceConnectionsType", + "validity": { + "type": "int", + "defaultValue": 12, + "minValue": 1, + "maxValue": 1200, "metadata": { - "description": "Optional. A grouping of information about the connection to the remote resource." + "description": "Optional. Override default validityInMonths 12 value" } }, - "enableTelemetry": { + "performRoleAssignment": { "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." + "description": "Set to false to disable role assignments within this module. Default: true" } } }, "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')]" - } + "$fxv#0": "#!/bin/bash\nset -e\ninitialDelay=\"${initialDelay:-5}\"\nretryMax=\"${retryMax:-5}\"\ncertName=\"${certName:-default-cert}\"\ncertCommonName=\"${certCommonName:-default}\"\nvalidity=\"${validity:-12}\"\nakvName=\"${akvName:-keyvault}\"\nissuerName=\"${issuerName:-}\"\nreuseKey=\"${reuseKey:-true}\"\nretrySleep=\"${retrySleep:-5}\"\n\necho \"Waiting on Identity RBAC replication (\\\"$initialDelay\\\")\"\nsleep \"$initialDelay\"\n\n#Retry loop to catch errors (usually RBAC delays)\nretryLoopCount=0\nuntil [ \"$retryLoopCount\" -ge \"$retryMax\" ]\ndo\n echo \"Creating AKV Cert $certName with CN $certCommonName (attempt $retryLoopCount)...\"\n\n if [ -z \"$issuerName\" ] || [ -z \"$issuerProvider\" ]; then\n policy=$(az keyvault certificate get-default-policy \\\n | sed -e s/\\\"validityInMonths\\\":\\ 12/\\\"validityInMonths\\\":\\ \"${validity}\"/g \\\n | sed -e s/CN=CLIGetDefaultPolicy/CN=\"${certCommonName}\"/g )\n else\n if [ \"$issuerProvider\" == \"DigiCert\" ] || [ \"$issuerProvider\" == \"GlobalCert\" ]; then\n az keyvault certificate issuer create \\\n --vault-name \"$akvName\" \\\n --issuer-name \"$issuerName\" \\\n --provider-name \"$issuerProvider\" \\\n --account-id \"$accountId\" \\\n --password \"$issuerPassword\" \\\n --organizatiion-id \"$organizationId\"\n else\n az keyvault certificate issuer create \\\n --vault-name \"$akvName\" \\\n --issuer-name \"$issuerName\" \\\n --provider-name \"$issuerProvider\"\n fi\n policy=$(az keyvault certificate get-default-policy \\\n | sed -e s/\\\"validityInMonths\\\":\\ 12/\\\"validityInMonths\\\":\\ \"${validity}\"/g \\\n | sed -e s/CN=CLIGetDefaultPolicy/CN=\"${certCommonName}\"/g \\\n | sed -e s/\\\"name\\\":\\ \\\"Self\\\"/\\\"name\\\":\\ \\\"\"${issuerName}\"\\\"/g \\\n | sed -e s/\\\"reuseKey\\\":\\ true/\\\"reuseKey\\\":\\ \"${reuseKey}\"/g )\n fi\n az keyvault certificate create \\\n --vault-name \"$akvName\" \\\n -n \"$certName\" \\\n -p \"$policy\" \\\n --disabled \"$disabled\" \\\n && break\n\n sleep \"$retrySleep\"\n retryLoopCount=$((retryLoopCount+1))\ndone\n\necho \"Getting Certificate $certName\";\nretryLoopCount=0\ncreatedCert=$(az keyvault certificate show -n \"$certName\" --vault-name \"$akvName\" -o json)\nwhile [ -z \"$(echo \"$createdCert\" | jq -r '.x509ThumbprintHex')\" ] && [ $retryLoopCount -lt \"$retryMax\" ]\ndo\n echo \"Waiting for cert creation (attempt $retryLoopCount)...\"\n sleep $retrySleep\n createdCert=$(az keyvault certificate show -n $certName --vault-name $akvName -o json)\n retryLoopCount=$((retryLoopCount+1))\ndone\n\nunversionedSecretId=$(echo $createdCert | jq -r \".sid\" | cut -d'/' -f-5) # remove the version from the url;\njsonOutputString=$(echo $createdCert | jq --arg usid $unversionedSecretId '{name: .name ,certSecretId: {versioned: .sid, unversioned: $usid }, thumbprint: .x509Thumbprint, thumbprintHex: .x509ThumbprintHex}')\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH", + "delegatedManagedIdentityResourceId": "[if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]" }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.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')]", + "resources": [ + { + "condition": "[not(parameters('useExistingManagedIdentity'))]", + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", + "name": "[parameters('managedIdentityName')]", "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')]" - } + "metadata": { + "description": "A new managed identity that will be created in this Resource Group, this is the default option" } }, - "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')))]", + { + "condition": "[parameters('performRoleAssignment')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", + "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRolesNeededOnKV'), parameters('managedIdentityName'), string(parameters('useExistingManagedIdentity')))]", "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.')]" + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeededOnKV'))]", + "principalId": "[if(parameters('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2018-11-30').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2018-11-30').principalId)]", + "principalType": "ServicePrincipal", + "delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]" }, "dependsOn": [ - "privateEndpoint" + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" ] }, - "privateEndpoint_roleAssignments": { + { "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + "name": "createImportCerts", + "count": "[length(parameters('certificateNames'))]" }, - "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')]" + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2020-10-01", + "name": "[format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} + } }, - "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))]", + "kind": "AzureCLI", "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "azCliVersion": "2.35.0", + "timeout": "PT10M", + "retentionInterval": "P1D", + "environmentVariables": [ + { + "name": "akvName", + "value": "[parameters('kvName')]" }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + { + "name": "certName", + "value": "[parameters('certificateNames')[copyIndex()]]" }, - "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.23.1.45101", - "templateHash": "18168683629401652671" - }, - "name": "Private Endpoint Private DNS Zone Groups", - "description": "This module deploys a Private Endpoint Private DNS Zone Group.", - "owner": "Azure/module-maintainers" + { + "name": "certCommonName", + "value": "[parameters('certificateCommonNames')[copyIndex()]]" }, - "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." - } - } + { + "name": "initialDelay", + "value": "[parameters('initialScriptDelay')]" }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } - } - ] + { + "name": "issuerName", + "value": "[parameters('issuerName')]" }, - "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]" - } + { + "name": "issuerProvider", + "value": "[parameters('issuerProvider')]" + }, + { + "name": "disabled", + "value": "[toLower(string(parameters('disabled')))]" + }, + { + "name": "retryMax", + "value": "10" + }, + { + "name": "retrySleep", + "value": "5s" + }, + { + "name": "accountId", + "value": "[parameters('accountId')]" + }, + { + "name": "issuerPassword", + "secureValue": "[parameters('issuerPassword')]" + }, + { + "name": "organizationId", + "value": "[parameters('organizationId')]" + }, + { + "name": "reuseKey", + "value": "[toLower(string(parameters('reuseKey')))]" + }, + { + "name": "validity", + "value": "[string(parameters('validity'))]" } - } + ], + "scriptContent": "[variables('$fxv#0')]", + "cleanupPreference": "[parameters('cleanupPreference')]" }, "dependsOn": [ - "privateEndpoint" + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", + "[extensionResourceId(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRolesNeededOnKV'), parameters('managedIdentityName'), string(parameters('useExistingManagedIdentity'))))]" ] } - }, + ], "outputs": { - "resourceGroupName": { - "type": "string", + "certificateNames": { + "type": "array", "metadata": { - "description": "The resource group the private endpoint was deployed into." + "description": "Certificate names" }, - "value": "[resourceGroup().name]" + "copy": { + "count": "[length(parameters('certificateNames'))]", + "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.name)]" + } }, - "resourceId": { - "type": "string", + "certificateSecretIds": { + "type": "array", "metadata": { - "description": "The resource ID of the private endpoint." + "description": "KeyVault secret ids to the created version" }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + "copy": { + "count": "[length(parameters('certificateNames'))]", + "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.certSecretId.versioned)]" + } }, - "name": { - "type": "string", + "certificateSecretIdUnversioneds": { + "type": "array", "metadata": { - "description": "The name of the private endpoint." + "description": "KeyVault secret ids which uses the unversioned uri" }, - "value": "[parameters('name')]" + "copy": { + "count": "[length(parameters('certificateNames'))]", + "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.certSecretId.unversioned)]" + } }, - "location": { - "type": "string", + "certificateThumbpints": { + "type": "array", "metadata": { - "description": "The location the resource was deployed into." + "description": "Certificate Thumbprints" + }, + "copy": { + "count": "[length(parameters('certificateNames'))]", + "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.thumbprint)]" + } + }, + "certificateThumbprintHexs": { + "type": "array", + "metadata": { + "description": "Certificate Thumbprints (in hex)" }, - "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + "copy": { + "count": "[length(parameters('certificateNames'))]", + "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.thumbprintHex)]" + } } } } }, "dependsOn": [ - "keyVault" + "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]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-log-analytics-secrets', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "workspaceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "workspaceIdName": { - "value": "[variables('commonLayerConfig').secrets.logAnalyticsId]" - }, - "workspaceKeySecretName": { - "value": "[variables('commonLayerConfig').secrets.logAnalyticsKey]" - }, - "stampIdName": { - "value": "[variables('commonLayerConfig').secrets.stampIdentity]" - }, - "stampIdValue": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "16108987595482701916" - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the Analytics Workspace. Required if the template is used in a standalone deployment." - } - }, - "workspaceIdName": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "workspaceKeySecretName": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "stampIdName": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "stampIdValue": { - "type": "securestring", - "metadata": { - "description": "Required. The name of the secret." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('workspaceKeySecretName'))]", - "properties": { - "value": "[listKeys(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '2022-10-01').primarySharedKey]" - } }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('workspaceIdName'))]", - "properties": { - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - } - }, - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('stampIdName'))]", + "vaultEndpoint": { + "condition": "[parameters('enablePrivateLink')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault-pep', parameters('bladeConfig').sectionName)]", "properties": { - "value": "[parameters('stampIdValue')]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-keyvault-sshkey', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "kvName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "location": { - "value": "[parameters('location')]" - }, - "useExistingManagedIdentity": { - "value": true - }, - "managedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "existingManagedIdentitySubId": { - "value": "[subscription().subscriptionId]" - }, - "existingManagedIdentityResourceGroupName": { - "value": "[resourceGroup().name]" - }, - "sshKeyName": { - "value": "PrivateLinkSSHKey-" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9850304314810202810" - }, - "name": "SSH Key Pair", - "description": "This module creates a SSH Key Pair and stores it in an Azure Key Vault", - "owner": "azure-global-energy" - }, - "parameters": { - "kvName": { - "type": "string", - "metadata": { - "description": "The name of the Azure Key Vault" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "The location of the Key Vault and where to deploy the module resources to" - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "How the deployment script should be forced to execute" - } - }, - "rbacRoleNeeded": { - "type": "string", - "defaultValue": "b86a8fe4-44ce-4948-aee5-eccb2c155cd7", - "metadata": { - "description": "Azure RoleId that are required for the DeploymentScript resource to import images" - } - }, - "useExistingManagedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Does the Managed Identity already exists, or should be created" - } - }, - "managedIdentityName": { - "type": "string", - "defaultValue": "[format('id-keyvault-ssh-{0}', parameters('location'))]", - "metadata": { - "description": "Name of the Managed Identity resource" - } - }, - "existingManagedIdentitySubId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "For an existing Managed Identity, the Subscription Id it is located in" - } - }, - "existingManagedIdentityResourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "For an existing Managed Identity, the Resource Group it is located in" - } - }, - "sshKeyName": { - "type": "string", - "metadata": { - "description": "The name of the SSH Key to be created.\nif name is my-virtual-machine-ssh then the private key will be named my-virtual-machine-sshprivate and the public key will be named my-virtual-machine-sshpublic.\n" - } - }, - "initialScriptDelay": { - "type": "string", - "defaultValue": "30s", - "metadata": { - "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" - } - }, - "cleanupPreference": { - "type": "string", - "defaultValue": "OnSuccess", - "allowedValues": [ - "OnSuccess", - "OnExpiration", - "Always" - ], - "metadata": { - "description": "When the script resource is cleaned up" - } - } - }, - "variables": { - "$fxv#0": "#!/bin/bash\nset -e\n\necho \"Waiting on Identity RBAC replication ($initialDelay)\"\nsleep $initialDelay\n\n# Generate the SSH key pair\necho \"Generating SSH key pair...\"\n#ssh-keygen -t rsa -b 4096 -C \"azure@example.com\" -f id_rsa -N \"\"\nssh-keygen -m PEM -t rsa -b 4096 -f id_rsa -q\n\n# Import the private key and public key as strings\nprivateKey=$(cat id_rsa)\npublicKey=$(cat id_rsa.pub)\n\n# Re-Login to Azure CLI using the managed identity\necho \"Logging in to Azure CLI using managed identity...\"\naz login --identity\n\necho \"Storing secret ${sshKeyName}private in Key Vault $keyVaultName...\"\nprivSecret=$(az keyvault secret set --vault-name \"$keyVaultName\" --name \"${sshKeyNamePrivate}\" --value \"$privateKey\")\n\necho \"Storing secret ${sshKeyName}public in Key Vault $keyVaultName...\"\npubSecret=$(az keyvault secret set --vault-name \"$keyVaultName\" --name \"${sshKeyNamePublic}\" --value \"$publicKey\")\n\nprivateSecretId=$(echo $privSecret | jq -r \".id\" | cut -d'/' -f-5) # remove the version from the url;\npublicSecretId=$(echo $pubSecret | jq -r \".id\" | cut -d'/' -f-5) # remove the version from the url;\n\njsonOutputString=$(jq -cn --arg public $publicSecretId --arg private $privateSecretId '{secretUris: $ARGS.named}')\necho $jsonOutputString\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH\n\n# Cleanup\nrm -f id_rsa id_rsa.pub", - "privateKeySecretName": "[format('{0}private', parameters('sshKeyName'))]", - "publicKeySecretName": "[format('{0}public', parameters('sshKeyName'))]" - }, - "resources": [ - { - "condition": "[not(parameters('useExistingManagedIdentity'))]", - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[parameters('managedIdentityName')]", - "location": "[parameters('location')]" - }, - { - "condition": "[not(empty(parameters('rbacRoleNeeded')))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRoleNeeded'), if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRoleNeeded'))]", - "principalId": "[if(parameters('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId)]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" - ] - }, - { - "type": "Microsoft.Resources/deploymentScripts", - "apiVersion": "2020-10-01", - "name": "[format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('sshKeyName'), ':', ''), '/', '-'))]", - "location": "[parameters('location')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} - } - }, - "kind": "AzureCLI", - "properties": { - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "azCliVersion": "2.45.0", - "timeout": "PT15M", - "retentionInterval": "PT1H", - "environmentVariables": [ - { - "name": "keyVaultName", - "value": "[parameters('kvName')]" - }, - { - "name": "sshKeyNamePrivate", - "value": "[variables('privateKeySecretName')]" - }, - { - "name": "sshKeyNamePublic", - "value": "[variables('publicKeySecretName')]" - }, - { - "name": "initialDelay", - "value": "[parameters('initialScriptDelay')]" - } - ], - "scriptContent": "[variables('$fxv#0')]", - "cleanupPreference": "[parameters('cleanupPreference')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", - "[extensionResourceId(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRoleNeeded'), if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))))]" - ] - } - ], - "outputs": { - "publicKeyUri": { - "type": "string", - "metadata": { - "description": "The URI of the public key secret in the Key Vault" - }, - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('sshKeyName'), ':', ''), '/', '-'))), '2020-10-01').outputs.secretUris.public]" - }, - "privateKeyUri": { - "type": "string", - "metadata": { - "description": "The URI of the private key secret in the Key Vault" - }, - "value": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('sshKeyName'), ':', ''), '/', '-'))), '2020-10-01').outputs.secretUris.private]" - }, - "publicKeySecretName": { - "type": "string", - "metadata": { - "description": "The name of the public key secret in the Key Vault" - }, - "value": "[variables('publicKeySecretName')]" - }, - "privateKeySecretName": { - "type": "string", - "metadata": { - "description": "The name of the private key secret in the Key Vault" - }, - "value": "[variables('privateKeySecretName')]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-keyvault-cert', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "kvName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "location": { - "value": "[parameters('location')]" - }, - "useExistingManagedIdentity": { - "value": true - }, - "managedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "existingManagedIdentitySubId": { - "value": "[subscription().subscriptionId]" - }, - "existingManagedIdentityResourceGroupName": { - "value": "[resourceGroup().name]" - }, - "certificateNames": { - "value": [ - "https-certificate" - ] - }, - "initialScriptDelay": { - "value": "0" - }, - "validity": { - "value": 24 - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "2517950616202752509" - }, - "name": "Key Vault Certificate", - "description": "This module creates a Key Vault Certificate and stores it in an Azure Key Vault", - "owner": "azure-global-energy" - }, - "parameters": { - "kvName": { - "type": "string", - "metadata": { - "description": "The name of the Azure Key Vault" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location to deploy the resources to" - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "How the deployment script should be forced to execute" - } - }, - "rbacRolesNeededOnKV": { - "type": "string", - "defaultValue": "a4417e6f-fecd-4de8-b567-7b0420556985", - "metadata": { - "description": "The RoleDefinitionId required for the DeploymentScript resource to interact with KeyVault" - } - }, - "useExistingManagedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Does the Managed Identity already exists, or should be created" - } - }, - "managedIdentityName": { - "type": "string", - "defaultValue": "[format('id-KeyVaultCertificateCreator-{0}', parameters('location'))]", - "metadata": { - "description": "Name of the Managed Identity resource" - } - }, - "existingManagedIdentitySubId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "For an existing Managed Identity, the Subscription Id it is located in" - } - }, - "existingManagedIdentityResourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "For an existing Managed Identity, the Resource Group it is located in" - } - }, - "certificateNames": { - "type": "array", - "metadata": { - "description": "The names of the certificate to create. Use when creating many certificates." - } - }, - "certificateCommonNames": { - "type": "array", - "defaultValue": "[parameters('certificateNames')]", - "metadata": { - "description": "The common names of the certificate to create. Use when creating many certificates." - } - }, - "initialScriptDelay": { - "type": "string", - "defaultValue": "0", - "metadata": { - "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" - } - }, - "cleanupPreference": { - "type": "string", - "defaultValue": "OnSuccess", - "allowedValues": [ - "OnSuccess", - "OnExpiration", - "Always" - ], - "metadata": { - "description": "When the script resource is cleaned up" - } - }, - "issuerName": { - "type": "string", - "defaultValue": "Self", - "metadata": { - "description": "Self, or user defined {IssuerName} for certificate signing" - } - }, - "issuerProvider": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Certificate Issuer Provider, DigiCert, GlobalSign, or internal options may be used." - } - }, - "disabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Create certificate in disabled state. Default: false" - } - }, - "accountId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Account ID of Certificate Issuer Account" - } - }, - "issuerPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Password of Certificate Issuer Account" - } - }, - "organizationId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Organization ID of Certificate Issuer Account" - } - }, - "isCrossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Override this parameter if using this in cross tenant scenarios" - } - }, - "reuseKey": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "The default policy might cause errors about CSR being used before, so set this to false if that happens" - } - }, - "validity": { - "type": "int", - "defaultValue": 12, - "minValue": 1, - "maxValue": 1200, - "metadata": { - "description": "Optional. Override default validityInMonths 12 value" - } - }, - "performRoleAssignment": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Set to false to disable role assignments within this module. Default: true" - } - } - }, - "variables": { - "$fxv#0": "#!/bin/bash\nset -e\ninitialDelay=\"${initialDelay:-5}\"\nretryMax=\"${retryMax:-5}\"\ncertName=\"${certName:-default-cert}\"\ncertCommonName=\"${certCommonName:-default}\"\nvalidity=\"${validity:-12}\"\nakvName=\"${akvName:-keyvault}\"\nissuerName=\"${issuerName:-}\"\nreuseKey=\"${reuseKey:-true}\"\nretrySleep=\"${retrySleep:-5}\"\n\necho \"Waiting on Identity RBAC replication (\\\"$initialDelay\\\")\"\nsleep \"$initialDelay\"\n\n#Retry loop to catch errors (usually RBAC delays)\nretryLoopCount=0\nuntil [ \"$retryLoopCount\" -ge \"$retryMax\" ]\ndo\n echo \"Creating AKV Cert $certName with CN $certCommonName (attempt $retryLoopCount)...\"\n\n if [ -z \"$issuerName\" ] || [ -z \"$issuerProvider\" ]; then\n policy=$(az keyvault certificate get-default-policy \\\n | sed -e s/\\\"validityInMonths\\\":\\ 12/\\\"validityInMonths\\\":\\ \"${validity}\"/g \\\n | sed -e s/CN=CLIGetDefaultPolicy/CN=\"${certCommonName}\"/g )\n else\n if [ \"$issuerProvider\" == \"DigiCert\" ] || [ \"$issuerProvider\" == \"GlobalCert\" ]; then\n az keyvault certificate issuer create \\\n --vault-name \"$akvName\" \\\n --issuer-name \"$issuerName\" \\\n --provider-name \"$issuerProvider\" \\\n --account-id \"$accountId\" \\\n --password \"$issuerPassword\" \\\n --organizatiion-id \"$organizationId\"\n else\n az keyvault certificate issuer create \\\n --vault-name \"$akvName\" \\\n --issuer-name \"$issuerName\" \\\n --provider-name \"$issuerProvider\"\n fi\n policy=$(az keyvault certificate get-default-policy \\\n | sed -e s/\\\"validityInMonths\\\":\\ 12/\\\"validityInMonths\\\":\\ \"${validity}\"/g \\\n | sed -e s/CN=CLIGetDefaultPolicy/CN=\"${certCommonName}\"/g \\\n | sed -e s/\\\"name\\\":\\ \\\"Self\\\"/\\\"name\\\":\\ \\\"\"${issuerName}\"\\\"/g \\\n | sed -e s/\\\"reuseKey\\\":\\ true/\\\"reuseKey\\\":\\ \"${reuseKey}\"/g )\n fi\n az keyvault certificate create \\\n --vault-name \"$akvName\" \\\n -n \"$certName\" \\\n -p \"$policy\" \\\n --disabled \"$disabled\" \\\n && break\n\n sleep \"$retrySleep\"\n retryLoopCount=$((retryLoopCount+1))\ndone\n\necho \"Getting Certificate $certName\";\nretryLoopCount=0\ncreatedCert=$(az keyvault certificate show -n \"$certName\" --vault-name \"$akvName\" -o json)\nwhile [ -z \"$(echo \"$createdCert\" | jq -r '.x509ThumbprintHex')\" ] && [ $retryLoopCount -lt \"$retryMax\" ]\ndo\n echo \"Waiting for cert creation (attempt $retryLoopCount)...\"\n sleep $retrySleep\n createdCert=$(az keyvault certificate show -n $certName --vault-name $akvName -o json)\n retryLoopCount=$((retryLoopCount+1))\ndone\n\nunversionedSecretId=$(echo $createdCert | jq -r \".sid\" | cut -d'/' -f-5) # remove the version from the url;\njsonOutputString=$(echo $createdCert | jq --arg usid $unversionedSecretId '{name: .name ,certSecretId: {versioned: .sid, unversioned: $usid }, thumbprint: .x509Thumbprint, thumbprintHex: .x509ThumbprintHex}')\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH", - "delegatedManagedIdentityResourceId": "[if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]" - }, - "resources": [ - { - "condition": "[not(parameters('useExistingManagedIdentity'))]", - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2018-11-30", - "name": "[parameters('managedIdentityName')]", - "location": "[parameters('location')]", - "metadata": { - "description": "A new managed identity that will be created in this Resource Group, this is the default option" - } - }, - { - "condition": "[parameters('performRoleAssignment')]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", - "name": "[guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRolesNeededOnKV'), parameters('managedIdentityName'), string(parameters('useExistingManagedIdentity')))]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeededOnKV'))]", - "principalId": "[if(parameters('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2018-11-30').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2018-11-30').principalId)]", - "principalType": "ServicePrincipal", - "delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" - ] - }, - { - "copy": { - "name": "createImportCerts", - "count": "[length(parameters('certificateNames'))]" - }, - "type": "Microsoft.Resources/deploymentScripts", - "apiVersion": "2020-10-01", - "name": "[format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))]", - "location": "[parameters('location')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', if(parameters('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} - } - }, - "kind": "AzureCLI", - "properties": { - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "azCliVersion": "2.35.0", - "timeout": "PT10M", - "retentionInterval": "P1D", - "environmentVariables": [ - { - "name": "akvName", - "value": "[parameters('kvName')]" - }, - { - "name": "certName", - "value": "[parameters('certificateNames')[copyIndex()]]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceName": { + "value": "[reference('keyvault').outputs.name.value]" }, - { - "name": "certCommonName", - "value": "[parameters('certificateCommonNames')[copyIndex()]]" + "subnetResourceId": { + "value": "[parameters('subnetId')]" }, - { - "name": "initialDelay", - "value": "[parameters('initialScriptDelay')]" + "groupIds": { + "value": [ + "vault" + ] }, - { - "name": "issuerName", - "value": "[parameters('issuerName')]" + "privateDnsZoneGroup": { + "value": { + "privateDNSResourceIds": [ + "[resourceId('Microsoft.Network/privateDnsZones', 'privatelink.vaultcore.azure.net')]" + ] + } }, - { - "name": "issuerProvider", - "value": "[parameters('issuerProvider')]" - }, - { - "name": "disabled", - "value": "[toLower(string(parameters('disabled')))]" - }, - { - "name": "retryMax", - "value": "10" - }, - { - "name": "retrySleep", - "value": "5s" - }, - { - "name": "accountId", - "value": "[parameters('accountId')]" - }, - { - "name": "issuerPassword", - "secureValue": "[parameters('issuerPassword')]" - }, - { - "name": "organizationId", - "value": "[parameters('organizationId')]" - }, - { - "name": "reuseKey", - "value": "[toLower(string(parameters('reuseKey')))]" - }, - { - "name": "validity", - "value": "[string(parameters('validity'))]" - } - ], - "scriptContent": "[variables('$fxv#0')]", - "cleanupPreference": "[parameters('cleanupPreference')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", - "[extensionResourceId(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), parameters('rbacRolesNeededOnKV'), parameters('managedIdentityName'), string(parameters('useExistingManagedIdentity'))))]" - ] - } - ], - "outputs": { - "certificateNames": { - "type": "array", - "metadata": { - "description": "Certificate names" - }, - "copy": { - "count": "[length(parameters('certificateNames'))]", - "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.name)]" - } - }, - "certificateSecretIds": { - "type": "array", - "metadata": { - "description": "KeyVault secret ids to the created version" - }, - "copy": { - "count": "[length(parameters('certificateNames'))]", - "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.certSecretId.versioned)]" - } - }, - "certificateSecretIdUnversioneds": { - "type": "array", - "metadata": { - "description": "KeyVault secret ids which uses the unversioned uri" - }, - "copy": { - "count": "[length(parameters('certificateNames'))]", - "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.certSecretId.unversioned)]" - } - }, - "certificateThumbpints": { - "type": "array", - "metadata": { - "description": "Certificate Thumbprints" - }, - "copy": { - "count": "[length(parameters('certificateNames'))]", - "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.thumbprint)]" - } - }, - "certificateThumbprintHexs": { - "type": "array", - "metadata": { - "description": "Certificate Thumbprints (in hex)" - }, - "copy": { - "count": "[length(parameters('certificateNames'))]", - "input": "[createArray(reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('kvName'), replace(replace(parameters('certificateNames')[copyIndex()], ':', ''), '/', '-'))), '2020-10-01').outputs.thumbprintHex)]" - } - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-keyvault-pep', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "subnetResourceId": { - "value": "[format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))]" - }, - "groupIds": { - "value": [ - "vault" - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDNSResourceIds": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('vaultDNSZoneName'))]" - ] - } - }, - "serviceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4239594351844905205" - } - }, - "parameters": { - "resourceName": { - "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." - } - }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, - "applicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "defaultValue": [], - "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": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "customDnsConfigs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - } - }, - "variables": { - "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('resourceName')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" - }, - "privateEndpointName": { - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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.24.24.22086", - "templateHash": "2870098876496747977" - } + "serviceResourceId": { + "value": "[reference('keyvault').outputs.resourceId.value]" + } + }, + "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": "15826512194130576768" + } }, "parameters": { - "privateEndpointName": { + "resourceName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + "description": "Required. Name of the private endpoint resource to create." } }, - "privateDNSResourceIds": { - "type": "array", - "minLength": 1, - "maxLength": 5, + "subnetResourceId": { + "type": "string", "metadata": { - "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "resourceName": { + "serviceResourceId": { "type": "string", - "defaultValue": "default", "metadata": { - "description": "Optional. The name of the private DNS zone group." + "description": "Required. Resource ID of the resource that needs to be connected to the network." } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", - "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" - } - } + }, + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." } - ] - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + }, + "applicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } - } - ], - "outputs": { - "resourceGroupName": { + }, + "customNetworkInterfaceName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } }, - "name": { - "type": "string", + "ipConfigurations": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('resourceName')]" + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } }, - "id": { - "type": "string", + "privateDnsZoneGroup": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9895267498133017443" - } - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." } }, - "resourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." + "description": "Optional. Location for all Resources." } }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], + "crossTenant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." } }, - "description": { - "type": "string", - "defaultValue": "", + "roleAssignments": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" } }, - "condition": { - "type": "string", - "defaultValue": "", + "tags": { + "type": "object", + "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\"" + "description": "Tags." } }, - "conditionVersion": { + "lock": { "type": "string", - "defaultValue": "2.0", + "defaultValue": "NotSpecified", "allowedValues": [ - "2.0" + "CanNotDelete", + "NotSpecified", + "ReadOnly" ], "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Specify the type of lock." } }, - "crossTenant": { - "type": "bool", - "defaultValue": false, + "customDnsConfigs": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + "description": "Optional. Custom DNS configurations." } }, - "principals": { + "manualPrivateLinkServiceConnections": { "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + "description": "Optional. Manual PrivateLink Service Connections." } } }, "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" - } + "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" }, "resources": [ + { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", + "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", + "ipConfigurations": "[parameters('ipConfigurations')]", + "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[parameters('customDnsConfigs')]", + "privateLinkServiceConnections": [ + { + "name": "[parameters('resourceName')]", + "properties": { + "privateLinkServiceId": "[parameters('serviceResourceId')]", + "groupIds": "[parameters('groupIds')]" + } + } + ], + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDNSResourceIds": { + "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" + }, + "privateEndpointName": { + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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": "4839297301131483167" + } + }, + "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." + } + }, + "resourceName": { + "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": "2022-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('resourceName')]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, { "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" + "name": "privateEndpoint_roleAssignments", + "count": "[length(parameters('roleAssignments'))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Network/privateDnsZones', variables('vaultDNSZoneName'))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-storage', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('sa{0}{1}', replace(variables('commonLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('commonLayerConfig').name))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "diagnosticWorkspaceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - }, - "diagnosticLogsRetentionInDays": { - "value": 0 - }, - "sku": { - "value": "[variables('commonLayerConfig').storage.sku]" - }, - "tables": { - "value": "[variables('commonLayerConfig').storage.tables]" - }, - "shares": { - "value": "[variables('commonLayerConfig').storage.shares]" - }, - "allowBlobPublicAccess": { - "value": "[parameters('enableBlobPublicAccess')]" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Contributor", - "principals": [ - { - "id": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "resourceId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - } - ], - "principalType": "ServicePrincipal" - } - ] - }, - "cmekConfiguration": { - "value": "[parameters('cmekConfiguration')]" - }, - "keyVaultName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "storageAccountSecretName": { - "value": "[variables('commonLayerConfig').secrets.storageAccountName]" - }, - "storageAccountKeySecretName": { - "value": "[variables('commonLayerConfig').secrets.storageAccountKey]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "12218145875057312705" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Used to name all resources" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Resource Location." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard_LRS", - "allowedValues": [ - "Standard_LRS", - "Premium_LRS", - "Standard_GRS" - ], - "metadata": { - "description": "Specifies the storage account sku type." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Cool", - "Hot" - ], - "metadata": { - "description": "Specifies the storage account access tier." - } - }, - "containers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Storage Containers to be created." - } - }, - "tables": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Storage Tables to be created." - } - }, - "shares": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Storage Shares to be created." - } - }, - "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." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "diagnosticWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace." - } - }, - "diagnosticStorageAccountId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account." - } - }, - "diagnosticEventHubAuthorizationRuleId": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticEventHubName": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticLogsRetentionInDays": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." - } - }, - "logsToEnable": { - "type": "array", - "defaultValue": [ - "StorageRead", - "StorageWrite", - "StorageDelete" - ], - "allowedValues": [ - "StorageRead", - "StorageWrite", - "StorageDelete" - ], - "metadata": { - "description": "Optional. The name of logs that will be streamed." - } - }, - "metricsToEnable": { - "type": "array", - "defaultValue": [ - "AllMetrics" - ], - "allowedValues": [ - "AllMetrics" - ], - "metadata": { - "description": "Optional. The name of metrics that will be streamed." - } - }, - "cmekConfiguration": { - "type": "object", - "defaultValue": { - "kvUrl": "", - "keyName": "", - "identityId": "" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "10763501692852746164" + } + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" + } + } + } }, - "metadata": { - "description": "Optional. Customer Managed Encryption Key." - } - }, - "deleteRetention": { - "type": "int", - "defaultValue": 0, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Amount of days the soft deleted data is stored and available for recovery. 0 is off." - } + "dependsOn": [ + "keyvault", + "vaultDNSZone" + ] }, - "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." - } - }, - "privateLinkSettings": { - "type": "object", - "defaultValue": { - "subnetId": "1", - "vnetId": "1" - }, - "metadata": { - "description": "Settings Required to Enable Private Link" - } - }, - "keyVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Key Vault Name to store secrets into" - } - }, - "storageAccountSecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account name into vault set the secret name." - } - }, - "storageAccountKeySecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account key into vault set the secret name." - } - }, - "storageAccountConnectionString": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account connectionstring into vault set the secret name." - } - }, - "basetime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Optional: Current Date Time" - } - }, - "sasProperties": { - "type": "object", - "defaultValue": { - "signedServices": "b", - "signedPermission": "rl", - "signedExpiry": "[dateTimeAdd(parameters('basetime'), 'P1Y')]", - "signedResourceTypes": "sco", - "signedProtocol": "https" - }, - "metadata": { - "description": "Optional: Default SAS TOken Properties to download Blob." - } - }, - "saveToken": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional: To save storage account sas token into vault set the properties." - } - } - }, - "variables": { - "copy": [ - { - "name": "diagnosticsLogs", - "count": "[length(parameters('logsToEnable'))]", - "input": { - "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "diagnosticsMetrics", - "count": "[length(parameters('metricsToEnable'))]", - "input": { - "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", - "timeGrain": null, - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - } - ], - "enableCMEK": "[if(and(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), not(empty(parameters('cmekConfiguration').identityId))), true(), false())]", - "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", - "privateEndpointName": "[format('{0}-PrivateEndpoint', parameters('name'))]", - "publicDNSZoneForwarder": "[format('blob.{0}', environment().suffixes.storage)]", - "privateDnsZoneName": "[format('privatelink.{0}', variables('publicDNSZoneForwarder'))]" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "kind": "StorageV2", - "identity": "[if(variables('enableCMEK'), createObject('type', 'UserAssigned', 'userAssignedIdentities', createObject(format('{0}', parameters('cmekConfiguration').identityId), createObject())), null())]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "minimumTlsVersion": "TLS1_2", - "encryption": "[if(variables('enableCMEK'), createObject('identity', createObject('userAssignedIdentity', parameters('cmekConfiguration').identityId), 'services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Keyvault', 'keyvaultproperties', createObject('keyname', parameters('cmekConfiguration').keyName, 'keyvaulturi', parameters('cmekConfiguration').kvUrl)), createObject('services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Storage'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "networkAcls": "[if(variables('enablePrivateLink'), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'), createObject())]" - } - }, - { - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "properties": "[if(greater(parameters('deleteRetention'), 0), createObject('changeFeed', createObject('enabled', true()), 'restorePolicy', createObject('enabled', true(), 'days', 6), 'isVersioningEnabled', true(), 'deleteRetentionPolicy', createObject('enabled', true(), 'days', parameters('deleteRetention'))), createObject('deleteRetentionPolicy', createObject('enabled', false(), 'allowPermanentDelete', false())))]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "properties": {}, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "properties": { - "protocolSettings": {}, - "shareDeleteRetentionPolicy": { - "enabled": true, - "days": 7 - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "copy": { - "name": "storage_containers", - "count": "[length(parameters('containers'))]" - }, - "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('containers')[copyIndex()])]", - "properties": { - "defaultEncryptionScope": "$account-encryption-key", - "denyEncryptionScopeOverride": false, - "publicAccess": "None" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" - ] - }, - { - "copy": { - "name": "storage_tables", - "count": "[length(parameters('tables'))]" - }, - "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('tables')[copyIndex()])]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/tableServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" - ] - }, - { - "copy": { - "name": "fileShare", - "count": "[length(parameters('shares'))]" - }, - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('shares')[copyIndex()])]", - "properties": { - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/fileServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" - ] - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "name": "storage-diagnostics", - "properties": { - "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", - "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", - "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", - "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", - "metrics": "[variables('diagnosticsMetrics')]", - "logs": "[variables('diagnosticsLogs')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('privateDnsZoneName')]", - "location": "global", - "properties": {} - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-01-01", - "name": "[variables('privateEndpointName')]", - "location": "[parameters('location')]", - "properties": { - "privateLinkServiceConnections": [ - { - "name": "[variables('privateEndpointName')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", - "groupIds": [ - "blob" - ] - } - } - ], - "subnet": { - "id": "[parameters('privateLinkSettings').subnetId]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-01-01", - "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", - "properties": { - "privateDnsZoneConfigs": [ - { - "name": "dnsConfig", - "properties": { - "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]", - "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', variables('privateDnsZoneName'), 'link_to_vnet')]", - "location": "global", - "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[parameters('privateLinkSettings').vnetId]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" - ] - }, - { - "copy": { - "name": "storage_rbac", - "count": "[length(parameters('roleAssignments'))]" - }, + "configStorage": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-storage', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + "name": { + "value": "[format('sa{0}{1}', replace(parameters('bladeConfig').sectionName, '-', ''), uniqueString(resourceGroup().id, parameters('bladeConfig').sectionName))]" }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + "location": { + "value": "[parameters('location')]" }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17757352754536825728" + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" } }, - "parameters": { - "description": { - "type": "string", - "defaultValue": "" - }, - "principalType": { - "type": "string", - "defaultValue": "" - }, - "roleDefinitionIdOrName": { - "type": "string" - }, - "resourceId": { - "type": "string" - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "principals": { - "type": "array", - "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" - } - } + "diagnosticWorkspaceId": { + "value": "[parameters('workspaceResourceId')]" }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Avere Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a')]", - "Avere Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9')]", - "Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')]", - "Backup Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00c29273-979b-4161-815c-10b084fb9324')]", - "Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a795c7a0-d4a2-40c1-ae25-d81f01202912')]", - "Classic Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", - "Classic Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", - "Data Box Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'add466c9-e687-43fc-8d98-dfcf8d720be5')]", - "Data Box Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '028f4ed7-e2a9-465e-a8f4-9c0ffdfdc027')]", - "Data Lake Analytics Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '47b7735b-770e-4598-a7da-8b91488b4c88')]", - "Elastic SAN Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '80dcbedb-47ef-405d-95bd-188a1b4ac406')]", - "Elastic SAN Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'af6a70f8-3c9f-4105-acf1-d719e9fca4ca')]", - "Elastic SAN Volume Group Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8281131-f312-4f34-8d98-ae12be9f0d23')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "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', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "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')]" - } + "diagnosticLogsRetentionInDays": { + "value": 0 + }, + "sku": { + "value": "[variables('commonLayerConfig').storage.sku]" + }, + "tables": { + "value": "[variables('commonLayerConfig').storage.tables]" + }, + "shares": { + "value": "[variables('commonLayerConfig').storage.shares]" + }, + "allowBlobPublicAccess": { + "value": "[parameters('enableBlobPublicAccess')]" + }, + "cmekConfiguration": { + "value": "[parameters('cmekConfiguration')]" }, - "resources": [ - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(last(split(parameters('resourceId'), '/')), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", - "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountSecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-name', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { "keyVaultName": { - "value": "[parameters('keyVaultName')]" + "value": "[reference('keyvault').outputs.name.value]" }, - "name": { - "value": "[parameters('storageAccountSecretName')]" + "storageAccountSecretName": { + "value": "[variables('commonLayerConfig').secrets.storageAccountName]" }, - "value": { - "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]" + "storageAccountKeySecretName": { + "value": "[variables('commonLayerConfig').secrets.storageAccountKey]" } }, "template": { @@ -11744,1603 +10155,674 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" + "version": "0.25.53.49325", + "templateHash": "10199713575446331736" } }, "parameters": { - "keyVaultName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Used to name all resources" } }, - "name": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The name of the secret." + "description": "Resource Location." } }, - "value": { - "type": "securestring", + "tags": { + "type": "object", + "defaultValue": {}, "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" + "description": "Tags." } - } - ], - "outputs": { - "name": { + }, + "lock": { "type": "string", + "defaultValue": "NotSpecified", + "allowedValues": [ + "CanNotDelete", + "NotSpecified", + "ReadOnly" + ], "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" + "description": "Optional. Specify the type of lock." + } }, - "resourceId": { + "sku": { "type": "string", + "defaultValue": "Standard_LRS", + "allowedValues": [ + "Standard_LRS", + "Premium_LRS", + "Standard_GRS" + ], "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "description": "Specifies the storage account sku type." + } }, - "resourceGroupName": { + "accessTier": { "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Cool", + "Hot" + ], "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountKeySecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-key', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('storageAccountKeySecretName')]" - }, - "value": { - "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "parameters": { - "keyVaultName": { - "type": "string", + "description": "Specifies the storage account access tier." + } + }, + "containers": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Optional. Array of Storage Containers to be created." } }, - "name": { - "type": "string", + "tables": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. Array of Storage Tables to be created." } }, - "value": { - "type": "securestring", + "shares": { + "type": "array", + "defaultValue": [], "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." + "description": "Optional. Array of Storage Shares to be created." } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" + }, + "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)." } - } - ], - "outputs": { - "name": { + }, + "enabledProtocols": { "type": "string", + "defaultValue": "SMB", + "allowedValues": [ + "NFS", + "SMB" + ], "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" + "description": "Optional. The authentication protocol that is used for the file share. Can only be specified when creating a share." + } }, - "resourceId": { + "rootSquash": { "type": "string", + "defaultValue": "NoRootSquash", + "allowedValues": [ + "AllSquash", + "NoRootSquash", + "RootSquash" + ], "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "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." + } }, - "resourceGroupName": { + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" + } + }, + "diagnosticWorkspaceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountConnectionString'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-connectionstring', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('storageAccountConnectionString')]" - }, - "value": { - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value, environment().suffixes.storage)]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "parameters": { - "keyVaultName": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticStorageAccountId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Optional. Resource ID of the diagnostic storage account." } }, - "name": { + "diagnosticEventHubAuthorizationRuleId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The name of the secret." + "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." } }, - "value": { - "type": "securestring", + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", "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." + "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." } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." } - } - ], - "outputs": { - "name": { - "type": "string", + }, + "logsToEnable": { + "type": "array", + "defaultValue": [ + "StorageRead", + "StorageWrite", + "StorageDelete" + ], + "allowedValues": [ + "StorageRead", + "StorageWrite", + "StorageDelete" + ], "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" + "description": "Optional. The name of logs that will be streamed." + } }, - "resourceId": { - "type": "string", + "metricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], + "allowedValues": [ + "AllMetrics" + ], "metadata": { - "description": "The resource ID of the secret." + "description": "Optional. The name of metrics that will be streamed." + } + }, + "cmekConfiguration": { + "type": "object", + "defaultValue": { + "kvUrl": "", + "keyName": "", + "identityId": "" }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "metadata": { + "description": "Optional. Customer Managed Encryption Key." + } }, - "resourceGroupName": { - "type": "string", + "deleteRetention": { + "type": "int", + "defaultValue": 0, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Amount of days the soft deleted data is stored and available for recovery. 0 is off." + } + }, + "allowBlobPublicAccess": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the resource group the secret was created in." + "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." + } + }, + "privateLinkSettings": { + "type": "object", + "defaultValue": { + "subnetId": "1", + "vnetId": "1" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), parameters('saveToken'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-sasToken', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[format('{0}-SAS', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - }, - "value": { - "value": "[listAccountSAS(if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), '2022-05-01', parameters('sasProperties')).accountSasToken]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "parameters": { + "metadata": { + "description": "Settings Required to Enable Private Link" + } + }, "keyVaultName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Optional: Key Vault Name to store secrets into" } }, - "name": { + "storageAccountSecretName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The name of the secret." + "description": "Optional: To save storage account name into vault set the secret name." } }, - "value": { - "type": "securestring", + "storageAccountKeySecretName": { + "type": "string", + "defaultValue": "", "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" + "description": "Optional: To save storage account key into vault set the secret name." } - } - ], - "outputs": { - "name": { + }, + "storageAccountConnectionString": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" + "description": "Optional: To save storage account connectionstring into vault set the secret name." + } }, - "resourceId": { + "basetime": { "type": "string", + "defaultValue": "[utcNow('u')]", "metadata": { - "description": "The resource ID of the secret." + "description": "Optional: Current Date Time" + } + }, + "sasProperties": { + "type": "object", + "defaultValue": { + "signedServices": "b", + "signedPermission": "rl", + "signedExpiry": "[dateTimeAdd(parameters('basetime'), 'P1Y')]", + "signedResourceTypes": "sco", + "signedProtocol": "https" }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "metadata": { + "description": "Optional: Default SAS TOken Properties to download Blob." + } }, - "resourceGroupName": { - "type": "string", + "saveToken": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - } - ], - "outputs": { - "id": { - "type": "string", - "metadata": { - "description": "The resource ID." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the resource." - }, - "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-storage-endpoint', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "subnetResourceId": { - "value": "[format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))]" - }, - "serviceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage', variables('commonLayerConfig').name)), '2022-09-01').outputs.id.value]" - }, - "groupIds": { - "value": [ - "blob" - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDNSResourceIds": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('storageDnsZoneName'))]" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4239594351844905205" - } - }, - "parameters": { - "resourceName": { - "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." - } - }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, - "applicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "defaultValue": [], - "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": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "customDnsConfigs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - } - }, - "variables": { - "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('resourceName')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" - }, - "privateEndpointName": { - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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.24.24.22086", - "templateHash": "2870098876496747977" - } - }, - "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." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } + "description": "Optional: To save storage account sas token into vault set the properties." + } } }, "variables": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", + "name": "diagnosticsLogs", + "count": "[length(parameters('logsToEnable'))]", + "input": { + "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('metricsToEnable'))]", "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" } } } - ] + ], + "enableCMEK": "[if(and(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), not(empty(parameters('cmekConfiguration').identityId))), true(), false())]", + "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", + "privateEndpointName": "[format('{0}-PrivateEndpoint', parameters('name'))]", + "publicDNSZoneForwarder": "[format('blob.{0}', environment().suffixes.storage)]", + "privateDnsZoneName": "[format('privatelink.{0}', variables('publicDNSZoneForwarder'))]" }, "resources": [ { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "name": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "kind": "StorageV2", + "identity": "[if(variables('enableCMEK'), createObject('type', 'UserAssigned', 'userAssignedIdentities', createObject(format('{0}', parameters('cmekConfiguration').identityId), createObject())), null())]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + "accessTier": "[parameters('accessTier')]", + "minimumTlsVersion": "TLS1_2", + "encryption": "[if(variables('enableCMEK'), createObject('identity', createObject('userAssignedIdentity', parameters('cmekConfiguration').identityId), 'services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Keyvault', 'keyvaultproperties', createObject('keyname', parameters('cmekConfiguration').keyName, 'keyvaulturi', parameters('cmekConfiguration').kvUrl)), createObject('services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Storage'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "networkAcls": "[if(variables('enablePrivateLink'), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'), createObject())]" } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "properties": "[if(greater(parameters('deleteRetention'), 0), createObject('changeFeed', createObject('enabled', true()), 'restorePolicy', createObject('enabled', true(), 'days', 6), 'isVersioningEnabled', true(), 'deleteRetentionPolicy', createObject('enabled', true(), 'days', parameters('deleteRetention'))), createObject('deleteRetentionPolicy', createObject('enabled', false(), 'allowPermanentDelete', false())))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "properties": {}, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "properties": { + "protocolSettings": {}, + "shareDeleteRetentionPolicy": { + "enabled": true, + "days": 7 + } }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." + { + "copy": { + "name": "storage_containers", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('containers')[copyIndex()])]", + "properties": { + "defaultEncryptionScope": "$account-encryption-key", + "denyEncryptionScopeOverride": false, + "publicAccess": "None" }, - "value": "[parameters('resourceName')]" + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" + ] }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + { + "copy": { + "name": "storage_tables", + "count": "[length(parameters('tables'))]" }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9895267498133017443" - } - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." - } + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('tables')[copyIndex()])]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/tableServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" + ] }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." - } + { + "copy": { + "name": "fileShare", + "count": "[length(parameters('shares'))]" + }, + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('shares')[copyIndex()])]", + "properties": { + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/fileServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" + ] }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "name": "storage-diagnostics", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] }, - "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\"" - } + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('privateDnsZoneName')]", + "location": "global", + "properties": {} }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition." - } + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-01-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('location')]", + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", + "groupIds": [ + "blob" + ] + } + } + ], + "subnet": { + "id": "[parameters('privateLinkSettings').subnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2022-01-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "dnsConfig", + "properties": { + "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]", + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', variables('privateDnsZoneName'), 'link_to_vnet')]", + "location": "global", + "properties": { + "registrationEnabled": false, + "virtualNetwork": { + "id": "[parameters('privateLinkSettings').vnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + ] }, - "principals": { - "type": "array", - "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" - } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" - } - }, - "resources": [ { "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" + "name": "storage_rbac", + "count": "[length(parameters('roleAssignments'))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Network/privateDnsZones', variables('storageDnsZoneName'))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-cosmos-db', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[variables('commonLayerConfig').name]" - }, - "resourceLocation": { - "value": "[parameters('location')]" - }, - "tags": { - "value": { - "layer": "[variables('commonLayerConfig').displayName]" - } - }, - "diagnosticWorkspaceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - }, - "diagnosticLogsRetentionInDays": { - "value": 0 - }, - "capabilitiesToAdd": { - "value": [ - "EnableGremlin" - ] - }, - "gremlinDatabases": { - "value": [ - { - "name": "[variables('commonLayerConfig').database.name]", - "graphs": "[variables('commonLayerConfig').database.graphs]" - } - ] - }, - "throughput": { - "value": "[variables('commonLayerConfig').database.throughput]" - }, - "backupPolicyType": { - "value": "[variables('commonLayerConfig').database.backup]" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Contributor", - "principals": [ - { - "id": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "resourceId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - } - ], - "principalType": "ServicePrincipal" - } - ] - }, - "systemAssignedIdentity": { - "value": false - }, - "userAssignedIdentities": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', createObject(format('{0}', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value), createObject(), format('{0}', parameters('cmekConfiguration').identityId), createObject())), createObject('value', createObject(format('{0}', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value), createObject())))]", - "defaultIdentity": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', parameters('cmekConfiguration').identityId), createObject('value', ''))]", - "kvKeyUri": "[if(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), createObject('value', format('{0}/keys/{1}', parameters('cmekConfiguration').kvUrl, parameters('cmekConfiguration').keyName)), createObject('value', ''))]", - "keyVaultName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "databaseEndpointSecretName": { - "value": "[variables('commonLayerConfig').secrets.cosmosEndpoint]" - }, - "databasePrimaryKeySecretName": { - "value": "[variables('commonLayerConfig').secrets.cosmosPrimaryKey]" - }, - "databaseConnectionStringSecretName": { - "value": "[variables('commonLayerConfig').secrets.cosmosConnectionString]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "3234861563111276584" - } - }, - "parameters": { - "resourceName": { - "type": "string", - "minLength": 3, - "maxLength": 20, - "metadata": { - "description": "Used to name all resources" - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional: Resource Location." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "enableDeleteLock": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable lock to prevent accidental deletion" - } - }, - "multiwriteRegions": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Locations enabled for the Cosmos DB account." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." - } - }, - "defaultIdentity": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The default identity to be used." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. The offer type for the Cosmos DB database account." - } - }, - "defaultConsistencyLevel": { - "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. The default consistency level of the Cosmos DB account." - } - }, - "automaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable automatic failover for regions." - } - }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 10, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Max stale requests. Required for BoundedStaleness. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000." - } - }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, - "metadata": { - "description": "Optional. Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400." - } - }, - "serverVersion": { - "type": "string", - "defaultValue": "4.2", - "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2" - ], - "metadata": { - "description": "Optional. Specifies the MongoDB server version to use." - } - }, - "sqlDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. SQL Databases configurations." - } - }, - "gremlinDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Gremlin Databases configurations." - } - }, - "mongodbDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. MongoDB Databases configurations." - } - }, - "capabilitiesToAdd": { - "type": "array", - "defaultValue": [], - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless" - ], - "metadata": { - "description": "Optional. List of Cosmos DB capabilities for the account." - } - }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Periodic", - "allowedValues": [ - "Periodic", - "Continuous" - ], - "metadata": { - "description": "Optional. Describes the mode of backups." - } - }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], - "metadata": { - "description": "Optional. Configuration values for continuous mode backup." - } - }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, - "metadata": { - "description": "Optional. An integer representing the interval in minutes between two backups. Only applies to periodic backup type." - } - }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, - "metadata": { - "description": "Optional. An integer representing the time (in hours) that each backup is retained. Only applies to periodic backup type." - } - }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], - "metadata": { - "description": "Optional. Enum to indicate type of backup residency. Only applies to periodic backup type." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "diagnosticWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace." - } - }, - "diagnosticStorageAccountId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account." - } - }, - "diagnosticEventHubAuthorizationRuleId": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticEventHubName": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticLogsRetentionInDays": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." - } - }, - "logsToEnable": { - "type": "array", - "defaultValue": [ - "DataPlaneRequests", - "MongoRequests", - "QueryRuntimeStatistics", - "PartitionKeyStatistics", - "PartitionKeyRUConsumption", - "ControlPlaneRequests", - "CassandraRequests", - "GremlinRequests", - "TableApiRequests" - ], - "allowedValues": [ - "DataPlaneRequests", - "MongoRequests", - "QueryRuntimeStatistics", - "PartitionKeyStatistics", - "PartitionKeyRUConsumption", - "ControlPlaneRequests", - "CassandraRequests", - "GremlinRequests", - "TableApiRequests" - ], - "metadata": { - "description": "Optional. The name of logs that will be streamed." - } - }, - "metricsToEnable": { - "type": "array", - "defaultValue": [ - "Requests" - ], - "allowedValues": [ - "Requests" - ], - "metadata": { - "description": "Optional. The name of metrics that will be streamed." - } - }, - "kvKeyUri": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Customer Managed Encryption Key." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "privateLinkSettings": { - "type": "object", - "defaultValue": { - "subnetId": "1", - "vnetId": "1" - }, - "metadata": { - "description": "Settings Required to Enable Private Link" - } - }, - "keyVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Key Vault Name to store secrets into" - } - }, - "databaseEndpointSecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account name into vault set the secret hame." - } - }, - "databasePrimaryKeySecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account key into vault set the secret hame." - } - }, - "databaseConnectionStringSecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account connectionstring into vault set the secret hame." - } - } - }, - "variables": { - "copy": [ - { - "name": "diagnosticsLogs", - "count": "[length(parameters('logsToEnable'))]", - "input": { - "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "diagnosticsMetrics", - "count": "[length(parameters('metricsToEnable'))]", - "input": { - "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", - "timeGrain": null, - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "databaseAccount_locations", - "count": "[length(parameters('multiwriteRegions'))]", - "input": { - "failoverPriority": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].failoverPriority]", - "isZoneRedundant": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].isZoneRedundant]", - "locationName": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].locationName]" - } - }, - { - "name": "capabilities", - "count": "[length(parameters('capabilitiesToAdd'))]", - "input": { - "name": "[parameters('capabilitiesToAdd')[copyIndex('capabilities')]]" - } - } - ], - "name": "[format('dba-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "consistencyPolicy": { - "Eventual": { - "defaultConsistencyLevel": "Eventual" - }, - "ConsistentPrefix": { - "defaultConsistencyLevel": "ConsistentPrefix" - }, - "Session": { - "defaultConsistencyLevel": "Session" - }, - "BoundedStaleness": { - "defaultConsistencyLevel": "BoundedStaleness", - "maxStalenessPrefix": "[parameters('maxStalenessPrefix')]", - "maxIntervalInSeconds": "[parameters('maxIntervalInSeconds')]" - }, - "Strong": { - "defaultConsistencyLevel": "Strong" - } - }, - "kind": "[if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('gremlinDatabases')))), 'GlobalDocumentDB', if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'Parse'))]", - "backupPolicy": "[if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('type', parameters('backupPolicyType'), 'continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject('type', parameters('backupPolicyType'), 'periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))))]", - "databaseAccount_properties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType')), if(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', if(empty(parameters('multiwriteRegions')), false(), true()), 'locations', if(empty(parameters('multiwriteRegions')), createArray(createObject('failoverPriority', 0, 'isZoneRedundant', false(), 'locationName', parameters('resourceLocation'))), variables('databaseAccount_locations')), 'capabilities', variables('capabilities'), 'backupPolicy', variables('backupPolicy')), createObject()), if(not(empty(parameters('sqlDatabases'))), createObject('enableAutomaticFailover', parameters('automaticFailover'), 'AnalyticalStorageConfiguration', createObject('schemaType', 'WellDefined'), 'defaultIdentity', if(not(empty(parameters('defaultIdentity'))), format('UserAssignedIdentity={0}', parameters('defaultIdentity')), 'FirstPartyIdentity'), 'enablePartitionKeyMonitor', true(), 'enablePartitionMerge', false(), 'keyVaultKeyUri', if(not(empty(parameters('kvKeyUri'))), parameters('kvKeyUri'), json('null'))), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject('EnabledApiTypes', createArray('Sql'))))]", - "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", - "privateEndpointName": "[format('{0}-PrivateEndpoint', variables('name'))]", - "privateDNSZoneName": "privatelink.documents.azure.com" - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2022-08-15", - "name": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]", - "location": "[parameters('resourceLocation')]", - "tags": "[parameters('tags')]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), createObject())]" - }, - "kind": "[variables('kind')]", - "properties": "[variables('databaseAccount_properties')]" - }, - { - "condition": "[parameters('enableDeleteLock')]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "name": "[format('{0}-lock', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "properties": { - "level": "CanNotDelete" - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "name": "storage-diagnostics", - "properties": { - "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", - "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", - "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", - "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", - "metrics": "[variables('diagnosticsMetrics')]", - "logs": "[variables('diagnosticsLogs')]", - "logAnalyticsDestinationType": "AzureDiagnostics" - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2021-02-01", - "name": "[variables('privateEndpointName')]", - "location": "[parameters('resourceLocation')]", - "properties": { - "subnet": { - "id": "[parameters('privateLinkSettings').subnetId]" - }, - "privateLinkServiceConnections": [ - { - "name": "[variables('privateEndpointName')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "groupIds": [ - "Sql" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "18405904741015745823" + } + }, + "parameters": { + "description": { + "type": "string", + "defaultValue": "" + }, + "principalType": { + "type": "string", + "defaultValue": "" + }, + "roleDefinitionIdOrName": { + "type": "string" + }, + "resourceId": { + "type": "string" + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Avere Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a')]", + "Avere Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9')]", + "Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')]", + "Backup Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00c29273-979b-4161-815c-10b084fb9324')]", + "Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a795c7a0-d4a2-40c1-ae25-d81f01202912')]", + "Classic Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", + "Classic Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", + "Data Box Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'add466c9-e687-43fc-8d98-dfcf8d720be5')]", + "Data Box Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '028f4ed7-e2a9-465e-a8f4-9c0ffdfdc027')]", + "Data Lake Analytics Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '47b7735b-770e-4598-a7da-8b91488b4c88')]", + "Elastic SAN Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '80dcbedb-47ef-405d-95bd-188a1b4ac406')]", + "Elastic SAN Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'af6a70f8-3c9f-4105-acf1-d719e9fca4ca')]", + "Elastic SAN Volume Group Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8281131-f312-4f34-8d98-ae12be9f0d23')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "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', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "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')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(last(split(parameters('resourceId'), '/')), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" ] - } - } - ], - "customDnsConfigs": [ - { - "fqdn": "[variables('privateDNSZoneName')]" - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', variables('privateDNSZoneName'), format('{0}-link', variables('privateDNSZoneName')))]", - "location": "global", - "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[parameters('privateLinkSettings').vnetId]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('privateDNSZoneName')]", - "location": "global" - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-01-01", - "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", - "properties": { - "privateDnsZoneConfigs": [ - { - "name": "config1", - "properties": { - "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]", - "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" - ] - }, - { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(parameters('sqlDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, parameters('sqlDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" - }, - "name": { - "value": "[parameters('sqlDatabases')[copyIndex()].name]" - }, - "throughput": { - "value": "[parameters('throughput')]" - }, - "maxThroughput": { - "value": "[parameters('maxThroughput')]" - }, - "containers": "[if(contains(parameters('sqlDatabases')[copyIndex()], 'containers'), createObject('value', parameters('sqlDatabases')[copyIndex()].containers), createObject('value', 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.24.24.22086", - "templateHash": "6858371887559344148" - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the SQL database resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", - "resource": { - "id": "[parameters('name')]" - } - } }, { - "copy": { - "name": "container", - "count": "[length(parameters('containers'))]" - }, + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountSecretName'))))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}-sql-{2}', deployment().name, parameters('name'), copyIndex())]", + "name": "[format('{0}-secret-name', deployment().name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "sqlDatabaseName": { - "value": "[parameters('name')]" + "keyVaultName": { + "value": "[parameters('keyVaultName')]" }, "name": { - "value": "[parameters('containers')[copyIndex()].name]" + "value": "[parameters('storageAccountSecretName')]" }, - "paths": { - "value": "[parameters('containers')[copyIndex()].paths]" - }, - "kind": { - "value": "[parameters('containers')[copyIndex()].kind]" + "value": { + "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]" } }, "template": { @@ -13349,86 +10831,37 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "11447569482547394294" + "version": "0.25.53.49325", + "templateHash": "45035995711227405" } }, "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "sqlDatabaseName": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + "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. Name of the container." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the SQL Database resource." - } - }, - "paths": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of paths using which data within the container can be partitioned." + "description": "Required. The name of the secret." } }, - "uniqueKeyPaths": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of unique key paths using which data within the container can be partitioned." - } - }, - "kind": { - "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash", - "Range" - ], + "value": { + "type": "securestring", "metadata": { - "description": "Optional. Indicates the kind of algorithm used for partitioning." + "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." } } }, "resources": [ { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", "properties": { - "resource": { - "id": "[parameters('name')]", - "partitionKey": { - "paths": "[parameters('paths')]", - "kind": "[parameters('kind')]" - }, - "uniqueKeyPolicy": "[if(empty(parameters('uniqueKeyPaths')), null(), createObject('uniqueKeys', createArray(createObject('paths', parameters('uniqueKeyPaths')))))]" - }, - "options": "[if(or(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), equals(parameters('throughput'), -1)), null(), createObject('throughput', parameters('throughput')))]" + "value": "[parameters('value')]" } } ], @@ -13436,21 +10869,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the container." + "description": "The name of the secret." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the container." + "description": "The resource ID of the secret." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the container was created in." + "description": "The name of the resource group the secret was created in." }, "value": "[resourceGroup().name]" } @@ -13458,157 +10891,29 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(parameters('gremlinDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, parameters('gremlinDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" - }, - "name": { - "value": "[parameters('gremlinDatabases')[copyIndex()].name]" - }, - "throughput": { - "value": "[parameters('throughput')]" - }, - "maxThroughput": { - "value": "[parameters('maxThroughput')]" - }, - "graphs": "[if(contains(parameters('gremlinDatabases')[copyIndex()], 'graphs'), createObject('value', parameters('gremlinDatabases')[copyIndex()].graphs), createObject('value', 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.24.24.22086", - "templateHash": "18103380369028326266" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the Gremlin database resource." - } - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." - } - }, - "graphs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", - "resource": { - "id": "[parameters('name')]" - } - } }, { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(parameters('graphs'))]" - }, + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountKeySecretName'))))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}-graph-{2}', deployment().name, parameters('name'), parameters('graphs')[copyIndex()].name)]", + "name": "[format('{0}-secret-key', deployment().name)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[parameters('graphs')[copyIndex()].name]" - }, - "gremlinDatabaseName": { - "value": "[parameters('name')]" + "keyVaultName": { + "value": "[parameters('keyVaultName')]" }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" + "name": { + "value": "[parameters('storageAccountKeySecretName')]" }, - "automaticIndexing": "[if(contains(parameters('graphs')[copyIndex()], 'automaticIndexing'), createObject('value', parameters('graphs')[copyIndex()].automaticIndexing), createObject('value', true()))]", - "partitionKeyPaths": "[if(not(empty(parameters('graphs')[copyIndex()].partitionKeyPaths)), createObject('value', parameters('graphs')[copyIndex()].partitionKeyPaths), createObject('value', createArray()))]" + "value": { + "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -13616,67 +10921,37 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "1873938567172205337" + "version": "0.25.53.49325", + "templateHash": "45035995711227405" } }, "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the Gremlin graph resource." - } - }, - "databaseAccountName": { + "keyVaultName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." } }, - "gremlinDatabaseName": { + "name": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." - } - }, - "automaticIndexing": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates if the indexing policy is automatic." + "description": "Required. The name of the secret." } }, - "partitionKeyPaths": { - "type": "array", - "defaultValue": [], + "value": { + "type": "securestring", "metadata": { - "description": "Optional. List of paths using which data within the container can be partitioned." + "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." } } }, "resources": [ { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": { - "automatic": "[parameters('automaticIndexing')]" - }, - "partitionKey": { - "paths": "[if(not(empty(parameters('partitionKeyPaths'))), parameters('partitionKeyPaths'), null())]" - } - } + "value": "[parameters('value')]" } } ], @@ -13684,21 +10959,21 @@ "name": { "type": "string", "metadata": { - "description": "The name of the graph." + "description": "The name of the secret." }, "value": "[parameters('name')]" }, "resourceId": { "type": "string", "metadata": { - "description": "The resource ID of the graph." + "description": "The resource ID of the secret." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The name of the resource group the graph was created in." + "description": "The name of the resource group the secret was created in." }, "value": "[resourceGroup().name]" } @@ -13706,66 +10981,243 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountConnectionString'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-connectionstring', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('storageAccountConnectionString')]" + }, + "value": { + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value, environment().suffixes.storage)]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), parameters('saveToken'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-sasToken', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[format('{0}-SAS', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + }, + "value": { + "value": "[listAccountSAS(if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), '2022-05-01', parameters('sasProperties')).accountSasToken]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" ] } ], "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { + "id": { "type": "string", "metadata": { - "description": "The resource ID of the Gremlin database." + "description": "The resource ID." }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" }, - "resourceGroupName": { + "name": { "type": "string", "metadata": { - "description": "The name of the resource group the Gremlin database was created in." + "description": "The name of the resource." }, - "value": "[resourceGroup().name]" + "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + "keyvault" ] }, - { - "copy": { - "name": "databaseaccount_rbac", - "count": "[length(parameters('roleAssignments'))]" - }, + "storageEndpoint": { + "condition": "[parameters('enablePrivateLink')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-storage-endpoint', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" + "resourceName": { + "value": "[reference('configStorage').outputs.name.value]" }, - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + "subnetResourceId": { + "value": "[parameters('subnetId')]" }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + "serviceResourceId": { + "value": "[reference('configStorage').outputs.id.value]" }, - "crossTenant": { - "value": "[parameters('crossTenant')]" + "groupIds": { + "value": [ + "blob" + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDNSResourceIds": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('storageDnsZoneName'))]" + ] + } } }, "template": { @@ -13774,66 +11226,68 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4481649887391671234" + "version": "0.25.53.49325", + "templateHash": "15826512194130576768" } }, "parameters": { - "description": { + "resourceName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Required. Name of the private endpoint resource to create." } }, - "principals": { - "type": "array", + "subnetResourceId": { + "type": "string", "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "principalType": { + "serviceResourceId": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Required. Resource ID of the resource that needs to be connected to the network." } }, - "roleDefinitionIdOrName": { - "type": "string", + "groupIds": { + "type": "array", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." } }, - "resourceId": { - "type": "string", + "applicationSecurityGroups": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "condition": { + "customNetworkInterfaceName": { "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\"" + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "defaultValue": [], + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." } }, - "conditionVersion": { + "location": { "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Location for all Resources." } }, "crossTenant": { @@ -13842,165 +11296,437 @@ "metadata": { "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Managed Application Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')]", - "Managed Application Operator Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", - "Managed Applications Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Resource Policy Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": [ - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.DocumentDB/databaseAccounts', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", - "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseEndpointSecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-name', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('databaseEndpointSecretName')]" - }, - "value": { - "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').documentEndpoint]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "parameters": { - "keyVaultName": { - "type": "string", + }, + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Tags." } }, - "name": { + "lock": { "type": "string", + "defaultValue": "NotSpecified", + "allowedValues": [ + "CanNotDelete", + "NotSpecified", + "ReadOnly" + ], "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. Specify the type of lock." } }, - "value": { - "type": "securestring", + "customDnsConfigs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "defaultValue": [], "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." + "description": "Optional. Manual PrivateLink Service Connections." } } }, + "variables": { + "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" + }, "resources": [ { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "value": "[parameters('value')]" + "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", + "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", + "ipConfigurations": "[parameters('ipConfigurations')]", + "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[parameters('customDnsConfigs')]", + "privateLinkServiceConnections": [ + { + "name": "[parameters('resourceName')]", + "properties": { + "privateLinkServiceId": "[parameters('serviceResourceId')]", + "groupIds": "[parameters('groupIds')]" + } + } + ], + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } + }, + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDNSResourceIds": { + "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" + }, + "privateEndpointName": { + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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": "4839297301131483167" + } + }, + "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." + } + }, + "resourceName": { + "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": "2022-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('resourceName')]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(parameters('roleAssignments'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "10763501692852746164" + } + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] } ], "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the secret." + "description": "The name of the private endpoint." }, - "value": "[parameters('name')]" + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" }, - "resourceId": { + "id": { "type": "string", "metadata": { - "description": "The resource ID of the secret." + "description": "The resource ID of the private endpoint." }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The name of the resource group the secret was created in." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + "configStorage", + "storageDNSZone" ] }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databasePrimaryKeySecretName'))))]", + "database": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-key', deployment().name)]", + "name": "[format('{0}-cosmos-db', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { + "resourceName": { + "value": "[parameters('bladeConfig').sectionName]" + }, + "resourceLocation": { + "value": "[parameters('location')]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } + }, + "diagnosticWorkspaceId": { + "value": "[parameters('workspaceResourceId')]" + }, + "diagnosticLogsRetentionInDays": { + "value": 0 + }, + "capabilitiesToAdd": { + "value": [ + "EnableGremlin" + ] + }, + "gremlinDatabases": { + "value": [ + { + "name": "[variables('commonLayerConfig').database.name]", + "graphs": "[variables('commonLayerConfig').database.graphs]" + } + ] + }, + "throughput": { + "value": "[variables('commonLayerConfig').database.throughput]" + }, + "backupPolicyType": { + "value": "[variables('commonLayerConfig').database.backup]" + }, + "systemAssignedIdentity": { + "value": false + }, + "userAssignedIdentities": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', createObject(format('{0}', parameters('cmekConfiguration').identityId), createObject())), createObject('value', createObject()))]", + "defaultIdentity": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', parameters('cmekConfiguration').identityId), createObject('value', ''))]", + "kvKeyUri": "[if(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), createObject('value', format('{0}/keys/{1}', parameters('cmekConfiguration').kvUrl, parameters('cmekConfiguration').keyName)), createObject('value', ''))]", "keyVaultName": { - "value": "[parameters('keyVaultName')]" + "value": "[reference('keyvault').outputs.name.value]" }, - "name": { - "value": "[parameters('databasePrimaryKeySecretName')]" + "databaseEndpointSecretName": { + "value": "[variables('commonLayerConfig').secrets.cosmosEndpoint]" + }, + "databasePrimaryKeySecretName": { + "value": "[variables('commonLayerConfig').secrets.cosmosPrimaryKey]" }, - "value": { - "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').primaryMasterKey]" + "databaseConnectionStringSecretName": { + "value": "[variables('commonLayerConfig').secrets.cosmosConnectionString]" } }, "template": { @@ -14009,5618 +11735,1578 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" + "version": "0.25.53.49325", + "templateHash": "11940381066264844853" } }, "parameters": { - "keyVaultName": { + "resourceName": { "type": "string", + "minLength": 3, + "maxLength": 20, "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Used to name all resources" } }, - "name": { + "resourceLocation": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The name of the secret." + "description": "Optional: Resource Location." } }, - "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." + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags." } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" + }, + "enableDeleteLock": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable lock to prevent accidental deletion" } - } - ], - "outputs": { - "name": { + }, + "multiwriteRegions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Locations enabled for the Cosmos DB account." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + }, + "systemAssignedIdentity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The ID(s) to assign to the resource." + } + }, + "defaultIdentity": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" + "description": "Optional. The default identity to be used." + } }, - "resourceId": { + "databaseAccountOfferType": { "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "description": "Optional. The offer type for the Cosmos DB database account." + } }, - "resourceGroupName": { + "defaultConsistencyLevel": { "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], "metadata": { - "description": "The name of the resource group the secret was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseConnectionStringSecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-accountName', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('databaseConnectionStringSecretName')]" - }, - "value": { - "value": "[listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').connectionStrings[0].connectionString]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "parameters": { - "keyVaultName": { + "description": "Optional. The default consistency level of the Cosmos DB account." + } + }, + "automaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions." + } + }, + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 10, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Max stale requests. Required for BoundedStaleness. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400." + } + }, + "serverVersion": { "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2" + ], "metadata": { - "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + "description": "Optional. Specifies the MongoDB server version to use." } }, - "name": { + "sqlDatabases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. SQL Databases configurations." + } + }, + "gremlinDatabases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Gremlin Databases configurations." + } + }, + "mongodbDatabases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. MongoDB Databases configurations." + } + }, + "capabilitiesToAdd": { + "type": "array", + "defaultValue": [], + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless" + ], + "metadata": { + "description": "Optional. List of Cosmos DB capabilities for the account." + } + }, + "backupPolicyType": { "type": "string", + "defaultValue": "Periodic", + "allowedValues": [ + "Periodic", + "Continuous" + ], "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. Describes the mode of backups." } }, - "value": { - "type": "securestring", + "backupPolicyContinuousTier": { + "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], "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." + "description": "Optional. Configuration values for continuous mode backup." } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. Only applies to periodic backup type." } - } - ], - "outputs": { - "name": { + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, + "metadata": { + "description": "Optional. An integer representing the time (in hours) that each backup is retained. Only applies to periodic backup type." + } + }, + "backupStorageRedundancy": { "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], "metadata": { - "description": "The name of the secret." - }, - "value": "[parameters('name')]" + "description": "Optional. Enum to indicate type of backup residency. Only applies to periodic backup type." + } }, - "resourceId": { + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" + } + }, + "diagnosticWorkspaceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "The resource ID of the secret." - }, - "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } }, - "resourceGroupName": { + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "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." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "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." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "logsToEnable": { + "type": "array", + "defaultValue": [ + "DataPlaneRequests", + "MongoRequests", + "QueryRuntimeStatistics", + "PartitionKeyStatistics", + "PartitionKeyRUConsumption", + "ControlPlaneRequests", + "CassandraRequests", + "GremlinRequests", + "TableApiRequests" + ], + "allowedValues": [ + "DataPlaneRequests", + "MongoRequests", + "QueryRuntimeStatistics", + "PartitionKeyStatistics", + "PartitionKeyRUConsumption", + "ControlPlaneRequests", + "CassandraRequests", + "GremlinRequests", + "TableApiRequests" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed." + } + }, + "metricsToEnable": { + "type": "array", + "defaultValue": [ + "Requests" + ], + "allowedValues": [ + "Requests" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } + }, + "kvKeyUri": { "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Customer Managed Encryption Key." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the resource group the secret was created in." + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "privateLinkSettings": { + "type": "object", + "defaultValue": { + "subnetId": "1", + "vnetId": "1" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the database account." - }, - "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity, 'principalId')), reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity.principalId, '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-cosmos-db-endpoint', variables('commonLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "subnetResourceId": { - "value": "[format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))]" - }, - "serviceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db', variables('commonLayerConfig').name)), '2022-09-01').outputs.id.value]" - }, - "groupIds": { - "value": [ - "sql" - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDNSResourceIds": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('cosmosDnsZoneName'))]" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4239594351844905205" - } - }, - "parameters": { - "resourceName": { - "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." - } - }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, - "applicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "defaultValue": [], - "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": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "customDnsConfigs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - } - }, - "variables": { - "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('resourceName')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" - }, - "privateEndpointName": { - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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.24.24.22086", - "templateHash": "2870098876496747977" - } - }, - "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." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Optional. The name of the private DNS zone group." - } + "metadata": { + "description": "Settings Required to Enable Private Link" + } + }, + "keyVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Key Vault Name to store secrets into" + } + }, + "databaseEndpointSecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account name into vault set the secret hame." + } + }, + "databasePrimaryKeySecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account key into vault set the secret hame." + } + }, + "databaseConnectionStringSecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account connectionstring into vault set the secret hame." + } } }, "variables": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", + "name": "diagnosticsLogs", + "count": "[length(parameters('logsToEnable'))]", + "input": { + "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('metricsToEnable'))]", "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" } } + }, + { + "name": "databaseAccount_locations", + "count": "[length(parameters('multiwriteRegions'))]", + "input": { + "failoverPriority": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].failoverPriority]", + "isZoneRedundant": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].isZoneRedundant]", + "locationName": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].locationName]" + } + }, + { + "name": "capabilities", + "count": "[length(parameters('capabilitiesToAdd'))]", + "input": { + "name": "[parameters('capabilitiesToAdd')[copyIndex('capabilities')]]" + } } - ] + ], + "name": "[format('dba-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", + "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", + "consistencyPolicy": { + "Eventual": { + "defaultConsistencyLevel": "Eventual" + }, + "ConsistentPrefix": { + "defaultConsistencyLevel": "ConsistentPrefix" + }, + "Session": { + "defaultConsistencyLevel": "Session" + }, + "BoundedStaleness": { + "defaultConsistencyLevel": "BoundedStaleness", + "maxStalenessPrefix": "[parameters('maxStalenessPrefix')]", + "maxIntervalInSeconds": "[parameters('maxIntervalInSeconds')]" + }, + "Strong": { + "defaultConsistencyLevel": "Strong" + } + }, + "kind": "[if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('gremlinDatabases')))), 'GlobalDocumentDB', if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'Parse'))]", + "backupPolicy": "[if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('type', parameters('backupPolicyType'), 'continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject('type', parameters('backupPolicyType'), 'periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))))]", + "databaseAccount_properties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType')), if(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', if(empty(parameters('multiwriteRegions')), false(), true()), 'locations', if(empty(parameters('multiwriteRegions')), createArray(createObject('failoverPriority', 0, 'isZoneRedundant', false(), 'locationName', parameters('resourceLocation'))), variables('databaseAccount_locations')), 'capabilities', variables('capabilities'), 'backupPolicy', variables('backupPolicy')), createObject()), if(not(empty(parameters('sqlDatabases'))), createObject('enableAutomaticFailover', parameters('automaticFailover'), 'AnalyticalStorageConfiguration', createObject('schemaType', 'WellDefined'), 'defaultIdentity', if(not(empty(parameters('defaultIdentity'))), format('UserAssignedIdentity={0}', parameters('defaultIdentity')), 'FirstPartyIdentity'), 'enablePartitionKeyMonitor', true(), 'enablePartitionMerge', false(), 'keyVaultKeyUri', if(not(empty(parameters('kvKeyUri'))), parameters('kvKeyUri'), json('null'))), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject('EnabledApiTypes', createArray('Sql'))))]", + "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", + "privateEndpointName": "[format('{0}-PrivateEndpoint', variables('name'))]", + "privateDNSZoneName": "privatelink.documents.azure.com" }, "resources": [ { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2022-08-15", + "name": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]", + "location": "[parameters('resourceLocation')]", + "tags": "[parameters('tags')]", + "identity": { + "type": "[variables('identityType')]", + "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), createObject())]" + }, + "kind": "[variables('kind')]", + "properties": "[variables('databaseAccount_properties')]" + }, + { + "condition": "[parameters('enableDeleteLock')]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "name": "[format('{0}-lock', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "level": "CanNotDelete" }, - "value": "[resourceGroup().name]" + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "name": "storage-diagnostics", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]", + "logAnalyticsDestinationType": "AzureDiagnostics" }, - "value": "[parameters('resourceName')]" + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2021-02-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('resourceLocation')]", + "properties": { + "subnet": { + "id": "[parameters('privateLinkSettings').subnetId]" + }, + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "groupIds": [ + "Sql" + ] + } + } + ], + "customDnsConfigs": [ + { + "fqdn": "[variables('privateDNSZoneName')]" + } + ] }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9895267498133017443" - } - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." - } - }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', variables('privateDNSZoneName'), format('{0}-link', variables('privateDNSZoneName')))]", + "location": "global", + "properties": { + "registrationEnabled": false, + "virtualNetwork": { + "id": "[parameters('privateLinkSettings').vnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" + ] }, - "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\"" - } + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('privateDNSZoneName')]", + "location": "global" }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition." - } + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2022-01-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "config1", + "properties": { + "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]", + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } + { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(parameters('sqlDatabases'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, parameters('sqlDatabases')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" + }, + "name": { + "value": "[parameters('sqlDatabases')[copyIndex()].name]" + }, + "throughput": { + "value": "[parameters('throughput')]" + }, + "maxThroughput": { + "value": "[parameters('maxThroughput')]" + }, + "containers": "[if(contains(parameters('sqlDatabases')[copyIndex()], 'containers'), createObject('value', parameters('sqlDatabases')[copyIndex()].containers), createObject('value', 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.25.53.49325", + "templateHash": "6008495898597068380" + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the SQL database resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", + "resource": { + "id": "[parameters('name')]" + } + } + }, + { + "copy": { + "name": "container", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-sql-{2}', deployment().name, parameters('name'), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('containers')[copyIndex()].name]" + }, + "paths": { + "value": "[parameters('containers')[copyIndex()].paths]" + }, + "kind": { + "value": "[parameters('containers')[copyIndex()].kind]" + } + }, + "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": "8440494403171406302" + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the SQL Database resource." + } + }, + "paths": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of paths using which data within the container can be partitioned." + } + }, + "uniqueKeyPaths": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of unique key paths using which data within the container can be partitioned." + } + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash", + "Range" + ], + "metadata": { + "description": "Optional. Indicates the kind of algorithm used for partitioning." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "partitionKey": { + "paths": "[parameters('paths')]", + "kind": "[parameters('kind')]" + }, + "uniqueKeyPolicy": "[if(empty(parameters('uniqueKeyPaths')), null(), createObject('uniqueKeys', createArray(createObject('paths', parameters('uniqueKeyPaths')))))]" + }, + "options": "[if(or(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), equals(parameters('throughput'), -1)), null(), createObject('throughput', parameters('throughput')))]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "principals": { - "type": "array", - "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" - } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" - } - }, - "resources": [ { "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" + "name": "databaseAccount_gremlinDatabases", + "count": "[length(parameters('gremlinDatabases'))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, parameters('gremlinDatabases')[copyIndex()].name)]", "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('cosmosDnsZoneName'))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]" - ] - }, - { - "condition": "[parameters('enableBastion')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-bastion', variables('manageLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('bh-{0}{1}', replace(variables('manageLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('manageLayerConfig').name))]" - }, - "vNetId": { - "value": "[createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')]]" - }, - "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.23.1.45101", - "templateHash": "15023722152295838533" - }, - "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": { - "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." - } + "expressionEvaluationOptions": { + "scope": "inner" }, - "categoryGroup": { - "type": "string", - "nullable": true, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" + }, + "name": { + "value": "[parameters('gremlinDatabases')[copyIndex()].name]" + }, + "throughput": { + "value": "[parameters('throughput')]" + }, + "maxThroughput": { + "value": "[parameters('maxThroughput')]" + }, + "graphs": "[if(contains(parameters('gremlinDatabases')[copyIndex()], 'graphs'), createObject('value', parameters('gremlinDatabases')[copyIndex()].graphs), createObject('value', createArray()))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", "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." + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "7475748416791876520" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the Gremlin database resource." + } + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", + "resource": { + "id": "[parameters('name')]" + } + } + }, + { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(parameters('graphs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-graph-{2}', deployment().name, parameters('name'), parameters('graphs')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('graphs')[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "automaticIndexing": "[if(contains(parameters('graphs')[copyIndex()], 'automaticIndexing'), createObject('value', parameters('graphs')[copyIndex()].automaticIndexing), createObject('value', true()))]", + "partitionKeyPaths": "[if(not(empty(parameters('graphs')[copyIndex()].partitionKeyPaths)), createObject('value', parameters('graphs')[copyIndex()].partitionKeyPaths), createObject('value', 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.25.53.49325", + "templateHash": "6501375544323548839" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the Gremlin graph resource." + } + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "automaticIndexing": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates if the indexing policy is automatic." + } + }, + "partitionKeyPaths": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of paths using which data within the container can be partitioned." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": { + "automatic": "[parameters('automaticIndexing')]" + }, + "partitionKey": { + "paths": "[if(not(empty(parameters('partitionKeyPaths'))), parameters('partitionKeyPaths'), null())]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } } } - } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "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." - } - }, - "vNetId": { - "type": "string", - "metadata": { - "description": "Required. Shared services Virtual Network resource identifier." - } - }, - "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": { - "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.network-bastionhost.{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" - } - } - } - } - }, - "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('vNetId')))), 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": { - "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')]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", - "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(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.Network/bastionHosts', 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": [ - "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": "[if(contains(parameters('publicIPAddressObject'), 'publicIPAddressVersion'), createObject('value', parameters('publicIPAddressObject').publicIPAddressVersion), createObject('value', 'IPv4'))]", - "publicIPAllocationMethod": "[if(contains(parameters('publicIPAddressObject'), 'publicIPAllocationMethod'), createObject('value', parameters('publicIPAddressObject').publicIPAllocationMethod), createObject('value', 'Static'))]", - "publicIpPrefixResourceId": "[if(contains(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId'), createObject('value', parameters('publicIPAddressObject').publicIPPrefixResourceId), createObject('value', ''))]", - "roleAssignments": "[if(contains(parameters('publicIPAddressObject'), 'roleAssignments'), createObject('value', parameters('publicIPAddressObject').roleAssignments), createObject('value', createArray()))]", - "skuName": "[if(contains(parameters('publicIPAddressObject'), 'skuName'), createObject('value', parameters('publicIPAddressObject').skuName), createObject('value', 'Standard'))]", - "skuTier": "[if(contains(parameters('publicIPAddressObject'), 'skuTier'), createObject('value', parameters('publicIPAddressObject').skuTier), createObject('value', 'Regional'))]", - "tags": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" - }, - "zones": "[if(contains(parameters('publicIPAddressObject'), 'zones'), createObject('value', parameters('publicIPAddressObject').zones), createObject('value', 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.23.1.45101", - "templateHash": "3488076626994379707" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address.", - "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 - }, - "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 DDoS protection plan ID 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." - } - } - } - }, - "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." - } - } - } - }, - "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. 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", - "nullable": true, - "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": { - "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-publicipaddress.{0}.{1}', replace('0.2.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-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[parameters('zones')]", - "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": [] - } - }, - "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(parameters('roleAssignments'), 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)]", - "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": [ - "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": { - "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')]", - "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", - "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", - "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": "[if(contains(reference('publicIpAddress'), 'ipAddress'), reference('publicIpAddress').ipAddress, '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2023-04-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": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]" - ] - }, - { - "condition": "[parameters('enableBastion')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "virtualMachine", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "vmName": { - "value": "[format('vm-{0}{1}', replace(variables('manageLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('manageLayerConfig').name))]" - }, - "vmSize": { - "value": "[variables('manageLayerConfig').machine.vmSize]" - }, - "tags": { - "value": { - "layer": "[variables('manageLayerConfig').displayName]" - } - }, - "vmSubnetId": { - "value": "[format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('vmSubnetName'))]" - }, - "vmAdminPasswordOrKey": "[if(empty(parameters('vmAdminPasswordOrKey')), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value)), 'secretName', 'PrivateLinkSSHKey-public')), createObject('value', parameters('vmAdminPasswordOrKey')))]", - "vmAdminUsername": { - "value": "[parameters('vmAdminUsername')]" - }, - "workspaceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "authenticationType": "[if(empty(parameters('vmAdminPasswordOrKey')), createObject('value', 'sshPublicKey'), createObject('value', 'password'))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "10205852734751483933" - } - }, - "parameters": { - "vmName": { - "type": "string", - "defaultValue": "simpleVM", - "metadata": { - "description": "Specifies the name of the virtual machine." - } - }, - "vmSize": { - "type": "string", - "defaultValue": "Standard_D2s_v3", - "metadata": { - "description": "Specifies the size of the virtual machine." - } - }, - "vmSubnetId": { - "type": "string", - "metadata": { - "description": "Specifies the resource id of the subnet hosting the virtual machine." - } - }, - "imagePublisher": { - "type": "string", - "defaultValue": "Canonical", - "metadata": { - "description": "Specifies the image publisher of the disk image used to create the virtual machine." - } - }, - "imageOffer": { - "type": "string", - "defaultValue": "0001-com-ubuntu-server-jammy", - "metadata": { - "description": "Specifies the offer of the platform image or marketplace image used to create the virtual machine." - } - }, - "imageSku": { - "type": "string", - "defaultValue": "22_04-lts-gen2", - "metadata": { - "description": "Specifies the Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version." - } - }, - "authenticationType": { - "type": "string", - "defaultValue": "password", - "allowedValues": [ - "sshPublicKey", - "password" - ], - "metadata": { - "description": "Specifies the type of authentication when accessing the Virtual Machine. SSH key is recommended." - } - }, - "vmAdminUsername": { - "type": "string", - "metadata": { - "description": "Specifies the name of the administrator account of the virtual machine." - } - }, - "vmAdminPasswordOrKey": { - "type": "securestring", - "metadata": { - "description": "Specifies the SSH Key or password for the virtual machine. SSH key is recommended." - } - }, - "diskStorageAccountType": { - "type": "string", - "defaultValue": "Standard_LRS", - "allowedValues": [ - "Premium_LRS", - "StandardSSD_LRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Specifies the storage account type for OS and data disk." - } - }, - "numDataDisks": { - "type": "int", - "defaultValue": 0, - "minValue": 0, - "maxValue": 64, - "metadata": { - "description": "Specifies the number of data disks of the virtual machine." - } - }, - "osDiskSize": { - "type": "int", - "defaultValue": 30, - "metadata": { - "description": "Specifies the size in GB of the OS disk of the VM." - } - }, - "dataDiskSize": { - "type": "int", - "defaultValue": 50, - "metadata": { - "description": "Specifies the size in GB of the OS disk of the virtual machine." - } - }, - "dataDiskCaching": { - "type": "string", - "defaultValue": "ReadWrite", - "metadata": { - "description": "Specifies the caching requirements for the data disks." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Specifies the name of the Log Analytics workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Specifies the location." - } - }, - "tags": { - "type": "object", - "metadata": { - "description": "Specifies the resource tags." - } - } - }, - "variables": { - "vmNicName": "[format('{0}Nic', parameters('vmName'))]", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('vmAdminUsername'))]", - "keyData": "[parameters('vmAdminPasswordOrKey')]" - } - ] - }, - "provisionVMAgent": true - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-06-01", - "name": "[variables('vmNicName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "privateIPAllocationMethod": "Dynamic", - "subnet": { - "id": "[parameters('vmSubnetId')]" - } - } - } - ] - } - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2023-09-01", - "name": "[parameters('vmName')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('vmAdminUsername')]", - "adminPassword": "[parameters('vmAdminPasswordOrKey')]", - "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]" - }, - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(range(0, parameters('numDataDisks')))]", - "input": { - "caching": "[parameters('dataDiskCaching')]", - "diskSizeGB": "[parameters('dataDiskSize')]", - "lun": "[range(0, parameters('numDataDisks'))[copyIndex('dataDisks')]]", - "name": "[format('{0}-DataDisk{1}', parameters('vmName'), range(0, parameters('numDataDisks'))[copyIndex('dataDisks')])]", - "createOption": "Empty", - "managedDisk": { - "storageAccountType": "[parameters('diskStorageAccountType')]" - } - } - } - ], - "imageReference": { - "publisher": "[parameters('imagePublisher')]", - "offer": "[parameters('imageOffer')]", - "sku": "[parameters('imageSku')]", - "version": "latest" - }, - "osDisk": { - "name": "[format('{0}_OSDisk', parameters('vmName'))]", - "caching": "ReadWrite", - "createOption": "FromImage", - "diskSizeGB": "[parameters('osDiskSize')]", - "managedDisk": { - "storageAccountType": "[parameters('diskStorageAccountType')]" - } - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNicName'))]" - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNicName'))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('vmName'), 'LogAnalytics')]", - "location": "[parameters('location')]", - "properties": { - "publisher": "Microsoft.EnterpriseCloud.Monitoring", - "type": "OmsAgentForLinux", - "typeHandlerVersion": "1.17", - "settings": { - "workspaceId": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '2022-10-01').customerId]", - "stopOnMultipleConnections": false - }, - "protectedSettings": { - "workspaceKey": "[listKeys(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '2022-10-01').primarySharedKey]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]" - ] - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-bastion', variables('manageLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault-sshkey', variables('commonLayerConfig').name))]" - ] - }, - { - "copy": { - "name": "partitionStorage", - "count": "[length(parameters('partitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('sa{0}{1}', replace(format('data{0}{1}', copyIndex(), substring(uniqueString(parameters('partitions')[copyIndex()].name), 0, 6)), '-', ''), uniqueString(resourceGroup().id, format('data{0}{1}', copyIndex(), substring(uniqueString(parameters('partitions')[copyIndex()].name), 0, 6))))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": { - "layer": "[variables('partitionLayerConfig').displayName]", - "partition": "[parameters('partitions')[copyIndex()].name]", - "purpose": "data" - } - }, - "diagnosticWorkspaceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - }, - "diagnosticLogsRetentionInDays": { - "value": 0 - }, - "allowBlobPublicAccess": { - "value": "[parameters('enableBlobPublicAccess')]" - }, - "sku": { - "value": "[variables('partitionLayerConfig').storage.sku]" - }, - "containers": { - "value": "[concat(variables('partitionLayerConfig').storage.containers, createArray(parameters('partitions')[copyIndex()].name))]" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Contributor", - "principals": [ - { - "id": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "resourceId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - } - ], - "principalType": "ServicePrincipal" - } - ] - }, - "cmekConfiguration": { - "value": "[parameters('cmekConfiguration')]" - }, - "keyVaultName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "storageAccountSecretName": { - "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.storageAccountName)]" - }, - "storageAccountKeySecretName": { - "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.storageAccountKey)]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "12218145875057312705" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Used to name all resources" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Resource Location." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard_LRS", - "allowedValues": [ - "Standard_LRS", - "Premium_LRS", - "Standard_GRS" - ], - "metadata": { - "description": "Specifies the storage account sku type." - } - }, - "accessTier": { - "type": "string", - "defaultValue": "Hot", - "allowedValues": [ - "Cool", - "Hot" - ], - "metadata": { - "description": "Specifies the storage account access tier." - } - }, - "containers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Storage Containers to be created." - } - }, - "tables": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Storage Tables to be created." - } - }, - "shares": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of Storage Shares to be created." - } - }, - "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." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "diagnosticWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace." - } - }, - "diagnosticStorageAccountId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account." - } - }, - "diagnosticEventHubAuthorizationRuleId": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticEventHubName": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticLogsRetentionInDays": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." - } - }, - "logsToEnable": { - "type": "array", - "defaultValue": [ - "StorageRead", - "StorageWrite", - "StorageDelete" - ], - "allowedValues": [ - "StorageRead", - "StorageWrite", - "StorageDelete" - ], - "metadata": { - "description": "Optional. The name of logs that will be streamed." - } - }, - "metricsToEnable": { - "type": "array", - "defaultValue": [ - "AllMetrics" - ], - "allowedValues": [ - "AllMetrics" - ], - "metadata": { - "description": "Optional. The name of metrics that will be streamed." - } - }, - "cmekConfiguration": { - "type": "object", - "defaultValue": { - "kvUrl": "", - "keyName": "", - "identityId": "" - }, - "metadata": { - "description": "Optional. Customer Managed Encryption Key." - } - }, - "deleteRetention": { - "type": "int", - "defaultValue": 0, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Amount of days the soft deleted data is stored and available for recovery. 0 is off." - } - }, - "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." - } - }, - "privateLinkSettings": { - "type": "object", - "defaultValue": { - "subnetId": "1", - "vnetId": "1" - }, - "metadata": { - "description": "Settings Required to Enable Private Link" - } - }, - "keyVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Key Vault Name to store secrets into" - } - }, - "storageAccountSecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account name into vault set the secret name." - } - }, - "storageAccountKeySecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account key into vault set the secret name." - } - }, - "storageAccountConnectionString": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account connectionstring into vault set the secret name." - } - }, - "basetime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Optional: Current Date Time" - } - }, - "sasProperties": { - "type": "object", - "defaultValue": { - "signedServices": "b", - "signedPermission": "rl", - "signedExpiry": "[dateTimeAdd(parameters('basetime'), 'P1Y')]", - "signedResourceTypes": "sco", - "signedProtocol": "https" - }, - "metadata": { - "description": "Optional: Default SAS TOken Properties to download Blob." - } - }, - "saveToken": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional: To save storage account sas token into vault set the properties." - } - } - }, - "variables": { - "copy": [ - { - "name": "diagnosticsLogs", - "count": "[length(parameters('logsToEnable'))]", - "input": { - "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "diagnosticsMetrics", - "count": "[length(parameters('metricsToEnable'))]", - "input": { - "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", - "timeGrain": null, - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - } - ], - "enableCMEK": "[if(and(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), not(empty(parameters('cmekConfiguration').identityId))), true(), false())]", - "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", - "privateEndpointName": "[format('{0}-PrivateEndpoint', parameters('name'))]", - "publicDNSZoneForwarder": "[format('blob.{0}', environment().suffixes.storage)]", - "privateDnsZoneName": "[format('privatelink.{0}', variables('publicDNSZoneForwarder'))]" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "kind": "StorageV2", - "identity": "[if(variables('enableCMEK'), createObject('type', 'UserAssigned', 'userAssignedIdentities', createObject(format('{0}', parameters('cmekConfiguration').identityId), createObject())), null())]", - "properties": { - "accessTier": "[parameters('accessTier')]", - "minimumTlsVersion": "TLS1_2", - "encryption": "[if(variables('enableCMEK'), createObject('identity', createObject('userAssignedIdentity', parameters('cmekConfiguration').identityId), 'services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Keyvault', 'keyvaultproperties', createObject('keyname', parameters('cmekConfiguration').keyName, 'keyvaulturi', parameters('cmekConfiguration').kvUrl)), createObject('services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Storage'))]", - "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", - "networkAcls": "[if(variables('enablePrivateLink'), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'), createObject())]" - } - }, - { - "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "properties": "[if(greater(parameters('deleteRetention'), 0), createObject('changeFeed', createObject('enabled', true()), 'restorePolicy', createObject('enabled', true(), 'days', 6), 'isVersioningEnabled', true(), 'deleteRetentionPolicy', createObject('enabled', true(), 'days', parameters('deleteRetention'))), createObject('deleteRetentionPolicy', createObject('enabled', false(), 'allowPermanentDelete', false())))]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "type": "Microsoft.Storage/storageAccounts/tableServices", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "properties": {}, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "properties": { - "protocolSettings": {}, - "shareDeleteRetentionPolicy": { - "enabled": true, - "days": 7 - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "copy": { - "name": "storage_containers", - "count": "[length(parameters('containers'))]" - }, - "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('containers')[copyIndex()])]", - "properties": { - "defaultEncryptionScope": "$account-encryption-key", - "denyEncryptionScopeOverride": false, - "publicAccess": "None" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" - ] - }, - { - "copy": { - "name": "storage_tables", - "count": "[length(parameters('tables'))]" - }, - "type": "Microsoft.Storage/storageAccounts/tableServices/tables", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('tables')[copyIndex()])]", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/tableServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" - ] - }, - { - "copy": { - "name": "fileShare", - "count": "[length(parameters('shares'))]" - }, - "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('shares')[copyIndex()])]", - "properties": { - "shareQuota": "[parameters('shareQuota')]", - "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", - "enabledProtocols": "[parameters('enabledProtocols')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/fileServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" - ] - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "name": "storage-diagnostics", - "properties": { - "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", - "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", - "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", - "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", - "metrics": "[variables('diagnosticsMetrics')]", - "logs": "[variables('diagnosticsLogs')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('privateDnsZoneName')]", - "location": "global", - "properties": {} - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-01-01", - "name": "[variables('privateEndpointName')]", - "location": "[parameters('location')]", - "properties": { - "privateLinkServiceConnections": [ - { - "name": "[variables('privateEndpointName')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", - "groupIds": [ - "blob" - ] - } - } - ], - "subnet": { - "id": "[parameters('privateLinkSettings').subnetId]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-01-01", - "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", - "properties": { - "privateDnsZoneConfigs": [ - { - "name": "dnsConfig", - "properties": { - "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]", - "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', variables('privateDnsZoneName'), 'link_to_vnet')]", - "location": "global", - "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[parameters('privateLinkSettings').vnetId]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" - ] - }, - { - "copy": { - "name": "storage_rbac", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17757352754536825728" - } - }, - "parameters": { - "description": { - "type": "string", - "defaultValue": "" - }, - "principalType": { - "type": "string", - "defaultValue": "" - }, - "roleDefinitionIdOrName": { - "type": "string" - }, - "resourceId": { - "type": "string" - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "principals": { - "type": "array", - "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" - } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Avere Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a')]", - "Avere Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9')]", - "Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')]", - "Backup Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00c29273-979b-4161-815c-10b084fb9324')]", - "Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a795c7a0-d4a2-40c1-ae25-d81f01202912')]", - "Classic Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", - "Classic Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", - "Data Box Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'add466c9-e687-43fc-8d98-dfcf8d720be5')]", - "Data Box Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '028f4ed7-e2a9-465e-a8f4-9c0ffdfdc027')]", - "Data Lake Analytics Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '47b7735b-770e-4598-a7da-8b91488b4c88')]", - "Elastic SAN Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '80dcbedb-47ef-405d-95bd-188a1b4ac406')]", - "Elastic SAN Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'af6a70f8-3c9f-4105-acf1-d719e9fca4ca')]", - "Elastic SAN Volume Group Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8281131-f312-4f34-8d98-ae12be9f0d23')]", - "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", - "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", - "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', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", - "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')]" - } - }, - "resources": [ - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(last(split(parameters('resourceId'), '/')), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", - "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", - "delegatedManagedIdentityResourceId": "[if(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountSecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-name', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('storageAccountSecretName')]" - }, - "value": { - "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), 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.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } - }, - "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" - } - } - ], - "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": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountKeySecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-key', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('storageAccountKeySecretName')]" - }, - "value": { - "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } - }, - "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" - } - } - ], - "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": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountConnectionString'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-connectionstring', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('storageAccountConnectionString')]" - }, - "value": { - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value, environment().suffixes.storage)]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } - }, - "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" - } - } - ], - "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": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), parameters('saveToken'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-sasToken', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[format('{0}-SAS', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - }, - "value": { - "value": "[listAccountSAS(if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), '2022-05-01', parameters('sasProperties')).accountSasToken]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } - }, - "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" - } - } - ], - "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": [ - "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - ] - } - ], - "outputs": { - "id": { - "type": "string", - "metadata": { - "description": "The resource ID." - }, - "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the resource." - }, - "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "copy": { - "name": "partitionStorageEndpoint", - "count": "[length(parameters('partitions'))]" - }, - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-azure-storage-endpoint-{1}', variables('partitionLayerConfig').name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex())), '2022-09-01').outputs.name.value]" - }, - "subnetResourceId": { - "value": "[format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))]" - }, - "serviceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex())), '2022-09-01').outputs.id.value]" - }, - "groupIds": { - "value": [ - "blob" - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDNSResourceIds": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('storageDnsZoneName'))]" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4239594351844905205" - } - }, - "parameters": { - "resourceName": { - "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." - } - }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, - "applicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "defaultValue": [], - "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": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "customDnsConfigs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - } - }, - "variables": { - "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('resourceName')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" - }, - "privateEndpointName": { - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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.24.24.22086", - "templateHash": "2870098876496747977" - } - }, - "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." - } - }, - "resourceName": { - "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": "2022-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('resourceName')]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9895267498133017443" - } - }, - "parameters": { - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." - } - }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "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", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "principals": { - "type": "array", - "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" - } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" - } - }, - "resources": [ - { - "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", - "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex()))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex()))]", - "[resourceId('Microsoft.Network/privateDnsZones', variables('storageDnsZoneName'))]" - ] - }, - { - "copy": { - "name": "partitionDb", - "count": "[length(parameters('partitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-cosmos-db-{1}', variables('partitionLayerConfig').name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[format('data{0}{1}', copyIndex(), substring(uniqueString(parameters('partitions')[copyIndex()].name), 0, 6))]" - }, - "resourceLocation": { - "value": "[parameters('location')]" - }, - "tags": { - "value": { - "layer": "[variables('partitionLayerConfig').displayName]", - "partition": "[parameters('partitions')[copyIndex()].name]", - "purpose": "data" - } - }, - "diagnosticWorkspaceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - }, - "diagnosticLogsRetentionInDays": { - "value": 0 - }, - "sqlDatabases": { - "value": [ - { - "name": "[variables('partitionLayerConfig').database.name]", - "containers": "[variables('partitionLayerConfig').database.containers]" - } - ] - }, - "maxThroughput": { - "value": "[variables('partitionLayerConfig').database[parameters('clusterSize')].throughput]" - }, - "backupPolicyType": { - "value": "[variables('partitionLayerConfig').database.backup]" - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Contributor", - "principals": [ - { - "id": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "resourceId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - } - ], - "principalType": "ServicePrincipal" - } - ] - }, - "systemAssignedIdentity": { - "value": false - }, - "userAssignedIdentities": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', createObject(format('{0}', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value), createObject(), format('{0}', parameters('cmekConfiguration').identityId), createObject())), createObject('value', createObject(format('{0}', reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value), createObject())))]", - "defaultIdentity": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', parameters('cmekConfiguration').identityId), createObject('value', ''))]", - "kvKeyUri": "[if(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), createObject('value', format('{0}/keys/{1}', parameters('cmekConfiguration').kvUrl, parameters('cmekConfiguration').keyName)), createObject('value', ''))]", - "keyVaultName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "databaseEndpointSecretName": { - "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.cosmosEndpoint)]" - }, - "databasePrimaryKeySecretName": { - "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.cosmosPrimaryKey)]" - }, - "databaseConnectionStringSecretName": { - "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.cosmosConnectionString)]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "3234861563111276584" - } - }, - "parameters": { - "resourceName": { - "type": "string", - "minLength": 3, - "maxLength": 20, - "metadata": { - "description": "Used to name all resources" - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional: Resource Location." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "enableDeleteLock": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable lock to prevent accidental deletion" - } - }, - "multiwriteRegions": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Locations enabled for the Cosmos DB account." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." - } - }, - "defaultIdentity": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The default identity to be used." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. The offer type for the Cosmos DB database account." - } - }, - "defaultConsistencyLevel": { - "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. The default consistency level of the Cosmos DB account." - } - }, - "automaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable automatic failover for regions." - } - }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 10, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Max stale requests. Required for BoundedStaleness. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000." - } - }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, - "metadata": { - "description": "Optional. Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400." - } - }, - "serverVersion": { - "type": "string", - "defaultValue": "4.2", - "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2" - ], - "metadata": { - "description": "Optional. Specifies the MongoDB server version to use." - } - }, - "sqlDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. SQL Databases configurations." - } - }, - "gremlinDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Gremlin Databases configurations." - } - }, - "mongodbDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. MongoDB Databases configurations." - } - }, - "capabilitiesToAdd": { - "type": "array", - "defaultValue": [], - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless" - ], - "metadata": { - "description": "Optional. List of Cosmos DB capabilities for the account." - } - }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Periodic", - "allowedValues": [ - "Periodic", - "Continuous" - ], - "metadata": { - "description": "Optional. Describes the mode of backups." - } - }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], - "metadata": { - "description": "Optional. Configuration values for continuous mode backup." - } - }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, - "metadata": { - "description": "Optional. An integer representing the interval in minutes between two backups. Only applies to periodic backup type." - } - }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, - "metadata": { - "description": "Optional. An integer representing the time (in hours) that each backup is retained. Only applies to periodic backup type." - } - }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], - "metadata": { - "description": "Optional. Enum to indicate type of backup residency. Only applies to periodic backup type." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "diagnosticWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace." - } - }, - "diagnosticStorageAccountId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account." - } - }, - "diagnosticEventHubAuthorizationRuleId": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticEventHubName": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticLogsRetentionInDays": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." - } - }, - "logsToEnable": { - "type": "array", - "defaultValue": [ - "DataPlaneRequests", - "MongoRequests", - "QueryRuntimeStatistics", - "PartitionKeyStatistics", - "PartitionKeyRUConsumption", - "ControlPlaneRequests", - "CassandraRequests", - "GremlinRequests", - "TableApiRequests" - ], - "allowedValues": [ - "DataPlaneRequests", - "MongoRequests", - "QueryRuntimeStatistics", - "PartitionKeyStatistics", - "PartitionKeyRUConsumption", - "ControlPlaneRequests", - "CassandraRequests", - "GremlinRequests", - "TableApiRequests" - ], - "metadata": { - "description": "Optional. The name of logs that will be streamed." - } - }, - "metricsToEnable": { - "type": "array", - "defaultValue": [ - "Requests" - ], - "allowedValues": [ - "Requests" - ], - "metadata": { - "description": "Optional. The name of metrics that will be streamed." - } - }, - "kvKeyUri": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Customer Managed Encryption Key." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "privateLinkSettings": { - "type": "object", - "defaultValue": { - "subnetId": "1", - "vnetId": "1" - }, - "metadata": { - "description": "Settings Required to Enable Private Link" - } - }, - "keyVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Key Vault Name to store secrets into" - } - }, - "databaseEndpointSecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account name into vault set the secret hame." - } - }, - "databasePrimaryKeySecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account key into vault set the secret hame." - } - }, - "databaseConnectionStringSecretName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: To save storage account connectionstring into vault set the secret hame." - } - } - }, - "variables": { - "copy": [ - { - "name": "diagnosticsLogs", - "count": "[length(parameters('logsToEnable'))]", - "input": { - "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "diagnosticsMetrics", - "count": "[length(parameters('metricsToEnable'))]", - "input": { - "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", - "timeGrain": null, - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "databaseAccount_locations", - "count": "[length(parameters('multiwriteRegions'))]", - "input": { - "failoverPriority": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].failoverPriority]", - "isZoneRedundant": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].isZoneRedundant]", - "locationName": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].locationName]" - } - }, - { - "name": "capabilities", - "count": "[length(parameters('capabilitiesToAdd'))]", - "input": { - "name": "[parameters('capabilitiesToAdd')[copyIndex('capabilities')]]" - } - } - ], - "name": "[format('dba-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", - "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "consistencyPolicy": { - "Eventual": { - "defaultConsistencyLevel": "Eventual" - }, - "ConsistentPrefix": { - "defaultConsistencyLevel": "ConsistentPrefix" - }, - "Session": { - "defaultConsistencyLevel": "Session" - }, - "BoundedStaleness": { - "defaultConsistencyLevel": "BoundedStaleness", - "maxStalenessPrefix": "[parameters('maxStalenessPrefix')]", - "maxIntervalInSeconds": "[parameters('maxIntervalInSeconds')]" - }, - "Strong": { - "defaultConsistencyLevel": "Strong" - } - }, - "kind": "[if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('gremlinDatabases')))), 'GlobalDocumentDB', if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'Parse'))]", - "backupPolicy": "[if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('type', parameters('backupPolicyType'), 'continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject('type', parameters('backupPolicyType'), 'periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))))]", - "databaseAccount_properties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType')), if(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', if(empty(parameters('multiwriteRegions')), false(), true()), 'locations', if(empty(parameters('multiwriteRegions')), createArray(createObject('failoverPriority', 0, 'isZoneRedundant', false(), 'locationName', parameters('resourceLocation'))), variables('databaseAccount_locations')), 'capabilities', variables('capabilities'), 'backupPolicy', variables('backupPolicy')), createObject()), if(not(empty(parameters('sqlDatabases'))), createObject('enableAutomaticFailover', parameters('automaticFailover'), 'AnalyticalStorageConfiguration', createObject('schemaType', 'WellDefined'), 'defaultIdentity', if(not(empty(parameters('defaultIdentity'))), format('UserAssignedIdentity={0}', parameters('defaultIdentity')), 'FirstPartyIdentity'), 'enablePartitionKeyMonitor', true(), 'enablePartitionMerge', false(), 'keyVaultKeyUri', if(not(empty(parameters('kvKeyUri'))), parameters('kvKeyUri'), json('null'))), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject('EnabledApiTypes', createArray('Sql'))))]", - "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", - "privateEndpointName": "[format('{0}-PrivateEndpoint', variables('name'))]", - "privateDNSZoneName": "privatelink.documents.azure.com" - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2022-08-15", - "name": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]", - "location": "[parameters('resourceLocation')]", - "tags": "[parameters('tags')]", - "identity": { - "type": "[variables('identityType')]", - "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), createObject())]" - }, - "kind": "[variables('kind')]", - "properties": "[variables('databaseAccount_properties')]" - }, - { - "condition": "[parameters('enableDeleteLock')]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "name": "[format('{0}-lock', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "properties": { - "level": "CanNotDelete" - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "name": "storage-diagnostics", - "properties": { - "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", - "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", - "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", - "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", - "metrics": "[variables('diagnosticsMetrics')]", - "logs": "[variables('diagnosticsLogs')]", - "logAnalyticsDestinationType": "AzureDiagnostics" - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2021-02-01", - "name": "[variables('privateEndpointName')]", - "location": "[parameters('resourceLocation')]", - "properties": { - "subnet": { - "id": "[parameters('privateLinkSettings').subnetId]" - }, - "privateLinkServiceConnections": [ - { - "name": "[variables('privateEndpointName')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", - "groupIds": [ - "Sql" - ] - } - } - ], - "customDnsConfigs": [ - { - "fqdn": "[variables('privateDNSZoneName')]" - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', variables('privateDNSZoneName'), format('{0}-link', variables('privateDNSZoneName')))]", - "location": "global", - "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[parameters('privateLinkSettings').vnetId]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('privateDNSZoneName')]", - "location": "global" - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-01-01", - "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", - "properties": { - "privateDnsZoneConfigs": [ - { - "name": "config1", - "properties": { - "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]", - "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" - ] - }, - { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(parameters('sqlDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, parameters('sqlDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" - }, - "name": { - "value": "[parameters('sqlDatabases')[copyIndex()].name]" - }, - "throughput": { - "value": "[parameters('throughput')]" - }, - "maxThroughput": { - "value": "[parameters('maxThroughput')]" - }, - "containers": "[if(contains(parameters('sqlDatabases')[copyIndex()], 'containers'), createObject('value', parameters('sqlDatabases')[copyIndex()].containers), createObject('value', 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.24.24.22086", - "templateHash": "6858371887559344148" - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the SQL database resource." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", - "resource": { - "id": "[parameters('name')]" - } - } - }, - { - "copy": { - "name": "container", - "count": "[length(parameters('containers'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}-sql-{2}', deployment().name, parameters('name'), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "sqlDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('containers')[copyIndex()].name]" - }, - "paths": { - "value": "[parameters('containers')[copyIndex()].paths]" - }, - "kind": { - "value": "[parameters('containers')[copyIndex()].kind]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "11447569482547394294" - } - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "sqlDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the SQL Database resource." - } - }, - "paths": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of paths using which data within the container can be partitioned." - } - }, - "uniqueKeyPaths": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of unique key paths using which data within the container can be partitioned." - } - }, - "kind": { - "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash", - "Range" - ], - "metadata": { - "description": "Optional. Indicates the kind of algorithm used for partitioning." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "partitionKey": { - "paths": "[parameters('paths')]", - "kind": "[parameters('kind')]" - }, - "uniqueKeyPolicy": "[if(empty(parameters('uniqueKeyPaths')), null(), createObject('uniqueKeys', createArray(createObject('paths', parameters('uniqueKeyPaths')))))]" - }, - "options": "[if(or(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), equals(parameters('throughput'), -1)), null(), createObject('throughput', parameters('throughput')))]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the container was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(parameters('gremlinDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, parameters('gremlinDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" - }, - "name": { - "value": "[parameters('gremlinDatabases')[copyIndex()].name]" - }, - "throughput": { - "value": "[parameters('throughput')]" - }, - "maxThroughput": { - "value": "[parameters('maxThroughput')]" - }, - "graphs": "[if(contains(parameters('gremlinDatabases')[copyIndex()], 'graphs'), createObject('value', parameters('gremlinDatabases')[copyIndex()].graphs), createObject('value', 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.24.24.22086", - "templateHash": "18103380369028326266" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the Gremlin database resource." - } - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." - } - }, - "graphs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", - "resource": { - "id": "[parameters('name')]" - } - } - }, - { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(parameters('graphs'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}-graph-{2}', deployment().name, parameters('name'), parameters('graphs')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('graphs')[copyIndex()].name]" - }, - "gremlinDatabaseName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "automaticIndexing": "[if(contains(parameters('graphs')[copyIndex()], 'automaticIndexing'), createObject('value', parameters('graphs')[copyIndex()].automaticIndexing), createObject('value', true()))]", - "partitionKeyPaths": "[if(not(empty(parameters('graphs')[copyIndex()].partitionKeyPaths)), createObject('value', parameters('graphs')[copyIndex()].partitionKeyPaths), createObject('value', 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.24.24.22086", - "templateHash": "1873938567172205337" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags of the Gremlin graph resource." - } - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "gremlinDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." - } - }, - "automaticIndexing": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates if the indexing policy is automatic." - } - }, - "partitionKeyPaths": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of paths using which data within the container can be partitioned." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2022-08-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": { - "automatic": "[parameters('automaticIndexing')]" - }, - "partitionKey": { - "paths": "[if(not(empty(parameters('partitionKeyPaths'))), parameters('partitionKeyPaths'), null())]" - } - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the graph." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the graph." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the graph was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Gremlin database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Gremlin database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "copy": { - "name": "databaseaccount_rbac", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" - }, - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - }, - "crossTenant": { - "value": "[parameters('crossTenant')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4481649887391671234" - } - }, - "parameters": { - "description": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The description of the role assignment." - } - }, - "principals": { - "type": "array", - "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" - } - }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." - } - }, - "roleDefinitionIdOrName": { - "type": "string", - "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." - } - }, - "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", - "defaultValue": "2.0", - "allowedValues": [ - "2.0" - ], - "metadata": { - "description": "Optional. Version of the condition." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - } - }, - "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Managed Application Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')]", - "Managed Application Operator Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", - "Managed Applications Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Resource Policy Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": [ { "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.DocumentDB/databaseAccounts', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", - "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseEndpointSecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-name', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('databaseEndpointSecretName')]" - }, - "value": { - "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').documentEndpoint]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } - }, - "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", - "properties": { - "value": "[parameters('value')]" - } - } - ], - "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." + "name": "databaseaccount_rbac", + "count": "[length(parameters('roleAssignments'))]" }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databasePrimaryKeySecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-key', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('databasePrimaryKeySecretName')]" - }, - "value": { - "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').primaryMasterKey]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } - }, - "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." - } - } - }, - "resources": [ - { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", "properties": { - "value": "[parameters('value')]" - } - } - ], - "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": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - }, - { - "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseConnectionStringSecretName'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-secret-accountName', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "name": { - "value": "[parameters('databaseConnectionStringSecretName')]" - }, - "value": { - "value": "[listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').connectionStrings[0].connectionString]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "17909531332154915378" - } - }, - "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." - } + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "4583229135454794215" + } + }, + "parameters": { + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Managed Application Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')]", + "Managed Application Operator Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", + "Managed Applications Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Resource Policy Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.DocumentDB/databaseAccounts', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "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." - } - } - }, - "resources": [ { - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2022-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseEndpointSecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-name', deployment().name)]", "properties": { - "value": "[parameters('value')]" - } - } - ], - "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": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the database account." - }, - "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedPrincipalId": { - "type": "string", - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity, 'principalId')), reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity.principalId, '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').location]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "copy": { - "name": "partitionDbEndpoint", - "count": "[length(parameters('partitions'))]" - }, - "condition": "[parameters('enablePrivateLink')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-cosmos-db-endpoint-{1}', variables('partitionLayerConfig').name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db-{1}', variables('partitionLayerConfig').name, copyIndex())), '2022-09-01').outputs.name.value]" - }, - "subnetResourceId": { - "value": "[format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))]" - }, - "serviceResourceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db-{1}', variables('partitionLayerConfig').name, copyIndex())), '2022-09-01').outputs.id.value]" - }, - "groupIds": { - "value": [ - "sql" - ] - }, - "privateDnsZoneGroup": { - "value": { - "privateDNSResourceIds": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('cosmosDnsZoneName'))]" - ] - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4239594351844905205" - } - }, - "parameters": { - "resourceName": { - "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." - } - }, - "serviceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource that needs to be connected to the network." - } - }, - "groupIds": { - "type": "array", - "metadata": { - "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." - } - }, - "applicationSecurityGroups": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "defaultValue": [], - "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": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "crossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "customDnsConfigs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Manual PrivateLink Service Connections." - } - } - }, - "variables": { - "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" - }, - "resources": [ - { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", - "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", - "ipConfigurations": "[parameters('ipConfigurations')]", - "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", - "customDnsConfigs": "[parameters('customDnsConfigs')]", - "privateLinkServiceConnections": [ - { - "name": "[parameters('resourceName')]", - "properties": { - "privateLinkServiceId": "[parameters('serviceResourceId')]", - "groupIds": "[parameters('groupIds')]" - } - } - ], - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" - ] - }, - { - "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDNSResourceIds": { - "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" - }, - "privateEndpointName": { - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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.24.24.22086", - "templateHash": "2870098876496747977" - } - }, - "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." - } + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('databaseEndpointSecretName')]" + }, + "value": { + "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').documentEndpoint]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] }, - "resourceName": { - "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')]]" + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databasePrimaryKeySecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-key', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('databasePrimaryKeySecretName')]" + }, + "value": { + "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').primaryMasterKey]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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]" + } } } - } - ] - }, - "resources": [ + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseConnectionStringSecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-accountName', deployment().name)]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('databaseConnectionStringSecretName')]" + }, + "value": { + "value": "[listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').connectionStrings[0].connectionString]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] } ], "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the database account." + }, + "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the database account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + }, "resourceGroupName": { "type": "string", "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." + "description": "The name of the resource group the database account was created in." }, "value": "[resourceGroup().name]" }, - "name": { + "systemAssignedPrincipalId": { "type": "string", "metadata": { - "description": "The name of the private endpoint DNS zone group." + "description": "The principal ID of the system assigned identity." }, - "value": "[parameters('resourceName')]" + "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity, 'principalId')), reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity.principalId, '')]" }, - "id": { + "location": { "type": "string", "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." + "description": "The location the resource was deployed into." }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" + "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').location]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + "keyvault" ] }, - { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(parameters('roleAssignments'))]" - }, + "graphEndpoint": { + "condition": "[parameters('enablePrivateLink')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-cosmos-db-endpoint', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principals": { - "value": "[parameters('roleAssignments')[copyIndex()].principals]" + "resourceName": { + "value": "[reference('database').outputs.name.value]" }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + "subnetResourceId": { + "value": "[parameters('subnetId')]" }, - "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + "serviceResourceId": { + "value": "[reference('database').outputs.id.value]" + }, + "groupIds": { + "value": [ + "sql" + ] }, - "crossTenant": { - "value": "[parameters('crossTenant')]" + "privateDnsZoneGroup": { + "value": { + "privateDNSResourceIds": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('cosmosDnsZoneName'))]" + ] + } } }, "template": { @@ -19629,2008 +13315,5679 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "9895267498133017443" + "version": "0.25.53.49325", + "templateHash": "15826512194130576768" } }, "parameters": { - "roleDefinitionIdOrName": { + "resourceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { "type": "string", "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource that needs to be connected to the network." + } + }, + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." + } + }, + "applicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "defaultValue": [], + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." } }, - "resourceId": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." + "description": "Optional. Location for all Resources." } }, - "principalType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], + "crossTenant": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." } }, - "description": { - "type": "string", - "defaultValue": "", + "roleAssignments": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. The description of the role assignment." + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" } }, - "condition": { - "type": "string", - "defaultValue": "", + "tags": { + "type": "object", + "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\"" + "description": "Tags." } }, - "conditionVersion": { + "lock": { "type": "string", - "defaultValue": "2.0", + "defaultValue": "NotSpecified", "allowedValues": [ - "2.0" + "CanNotDelete", + "NotSpecified", + "ReadOnly" ], "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. Specify the type of lock." } }, - "crossTenant": { - "type": "bool", - "defaultValue": false, + "customDnsConfigs": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + "description": "Optional. Custom DNS configurations." } }, - "principals": { + "manualPrivateLinkServiceConnections": { "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + "description": "Optional. Manual PrivateLink Service Connections." } } }, "variables": { - "builtInRoleNames": { - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" - } + "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" }, "resources": [ + { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", + "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", + "ipConfigurations": "[parameters('ipConfigurations')]", + "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[parameters('customDnsConfigs')]", + "privateLinkServiceConnections": [ + { + "name": "[parameters('resourceName')]", + "properties": { + "privateLinkServiceId": "[parameters('serviceResourceId')]", + "groupIds": "[parameters('groupIds')]" + } + } + ], + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDNSResourceIds": { + "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" + }, + "privateEndpointName": { + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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": "4839297301131483167" + } + }, + "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." + } + }, + "resourceName": { + "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": "2022-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('resourceName')]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, { "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principals'))]" + "name": "privateEndpoint_roleAssignments", + "count": "[length(parameters('roleAssignments'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "10763501692852746164" + } + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", - "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principals')[copyIndex()].id]", - "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" - } + "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" } - ] + } } }, "dependsOn": [ - "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + "cosmosDNSZone", + "database" ] } - ], + }, "outputs": { - "resourceGroupName": { + "keyvaultName": { "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[reference('keyvault').outputs.name.value]" }, - "name": { + "keyvaultUri": { "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" + "value": "[reference('keyvault').outputs.uri.value]" }, - "id": { + "storageAccountName": { "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + "value": "[reference('configStorage').outputs.name.value]" }, - "location": { + "storageDNSZoneId": { "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" + "value": "[resourceId('Microsoft.Network/privateDnsZones', variables('storageDnsZoneName'))]" + }, + "cosmosDNSZoneId": { + "type": "string", + "value": "[resourceId('Microsoft.Network/privateDnsZones', variables('cosmosDnsZoneName'))]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('cosmosDnsZoneName'))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db-{1}', variables('partitionLayerConfig').name, copyIndex()))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-cosmos-db-{1}', variables('partitionLayerConfig').name, copyIndex()))]" + "logAnalytics", + "networkBlade", + "stampIdentity" ] }, - { + "manageBlade": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-aks-cluster', variables('serviceLayerConfig').name)]", + "name": "manage-blade", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "resourceName": { - "value": "[variables('serviceLayerConfig').name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "aksVersion": { - "value": "[variables('serviceLayerConfig').cluster.aksVersion]" - }, - "aad_tenant_id": { - "value": "[subscription().tenantId]" - }, - "clusterSize": { - "value": "[parameters('clusterSize')]" - }, - "networkPlugin": { - "value": "[variables('serviceLayerConfig').cluster.networkPlugin]" - }, - "tags": { + "bladeConfig": { "value": { - "layer": "[variables('serviceLayerConfig').displayName]" + "sectionName": "manageblade", + "displayName": "Manage Resources" } }, - "aksSubnetId": "[if(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))))]", - "aksPodSubnetId": "[if(and(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), parameters('enablePodSubnet')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('podSubnetName'))), createObject('value', null()))]", - "identityId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - }, - "workspaceId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value]" - }, - "serviceCidr": { - "value": "[parameters('serviceCidr')]" - }, - "dnsServiceIP": { - "value": "[parameters('dnsServiceIP')]" - }, - "dockerBridgeCidr": { - "value": "[parameters('dockerBridgeCidr')]" - }, - "serviceMeshProfile": { - "value": "Istio" - }, - "istioRevision": { - "value": "[variables('serviceLayerConfig').cluster.meshVersion]" - }, - "istioIngressGatewayMode": { - "value": "[parameters('clusterIngress')]" + "manageLayerConfig": { + "value": { + "machine": { + "vmSize": "Standard_DS3_v2", + "imagePublisher": "Canonical", + "imageOffer": "UbuntuServer", + "imageSku": "18.04-LTS", + "authenticationType": "password" + }, + "bastion": { + "skuName": "Basic" + } + } }, - "enable_aad": "[if(equals(empty(parameters('clusterAdminIds')), true()), createObject('value', false()), createObject('value', true()))]", - "admin_ids": { - "value": "[parameters('clusterAdminIds')]" + "location": { + "value": "[parameters('location')]" }, - "workloadIdentityEnabled": { - "value": true + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" }, - "oidcIssuer": { - "value": true + "workspaceName": { + "value": "[reference('logAnalytics').outputs.name.value]" }, - "keyvaultEnabled": { - "value": true + "kvName": { + "value": "[reference('commonBlade').outputs.keyvaultName.value]" }, - "fluxGitOpsAddon": { - "value": true + "enableBastion": { + "value": "[parameters('enableBastion')]" }, - "enableImageCleaner": { - "value": true + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" }, - "fileCSIDriver": { - "value": true + "vmAdminPasswordOrKey": { + "value": "[parameters('vmAdminPasswordOrKey')]" }, - "blobCSIDriver": { - "value": true + "vnetId": { + "value": "[reference('networkBlade').outputs.vnetId.value]" }, - "azurepolicy": { - "value": "audit" + "vmSubnetId": { + "value": "[reference('networkBlade').outputs.vmSubnetId.value]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "16374876761694977329" - } - }, - "parameters": { - "resourceName": { - "type": "string", - "minLength": 1, - "maxLength": 63, - "metadata": { - "description": "Used to name all resources" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Specify the location of the AKS cluster." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "aad_tenant_id": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The ID of the Azure AD tenant" - } - }, - "admin_ids": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "The ID of the Azure AD tenant" - } - }, - "skuTierPaid": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Use the paid sku for SLA rather than SLO" - } - }, - "aksVersion": { - "type": "string", - "defaultValue": "1.28", - "metadata": { - "description": "Kubernetes Version" - } - }, - "upgradeChannel": { - "type": "string", - "defaultValue": "stable", - "allowedValues": [ - "none", - "patch", - "stable", - "rapid", - "node-image" - ], - "metadata": { - "description": "AKS upgrade channel" - } - }, - "managedNodeResourceGroup": { - "type": "string", - "defaultValue": "", - "maxLength": 80, - "metadata": { - "description": "The name of the NEW resource group to create the AKS cluster managed resources in" - } - }, - "clusterSize": { - "type": "string", - "defaultValue": "CostOptimised", - "allowedValues": [ - "CostOptimised", - "Standard", - "HighSpec", - "Custom" - ], - "metadata": { - "description": "The System Pool Preset sizing" - } - }, - "AutoscaleProfile": { - "type": "object", - "defaultValue": { - "balance-similar-node-groups": "true", - "expander": "random", - "max-empty-bulk-delete": "10", - "max-graceful-termination-sec": "600", - "max-node-provision-time": "15m", - "max-total-unready-percentage": "45", - "new-pod-scale-up-delay": "0s", - "ok-total-unready-count": "3", - "scale-down-delay-after-add": "10m", - "scale-down-delay-after-delete": "20s", - "scale-down-delay-after-failure": "3m", - "scale-down-unneeded-time": "10m", - "scale-down-unready-time": "20m", - "scale-down-utilization-threshold": "0.5", - "scan-interval": "10s", - "skip-nodes-with-local-storage": "true", - "skip-nodes-with-system-pods": "true" - }, - "metadata": { - "description": "The System Pool Preset sizing" - } - }, - "agentCount": { - "type": "int", - "defaultValue": 3, - "metadata": { - "description": "The number of agents for the user node pool" - } - }, - "agentCountMax": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "The maximum number of nodes for the user node pool" - } - }, - "nodePoolName": { - "type": "string", - "defaultValue": "internal", - "minLength": 3, - "maxLength": 12, - "metadata": { - "description": "Name for user node pool" - } - }, - "JustUseSystemPool": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Only use the system node pool" - } - }, - "workspaceId": { - "type": "string", - "metadata": { - "description": "Specify the Log Analytics Workspace Id to use for monitoring." - } - }, - "identityId": { - "type": "string", - "metadata": { - "description": "Specify the User Managed Identity Resource Id." - } - }, - "networkPlugin": { - "type": "string", - "defaultValue": "azure", - "allowedValues": [ - "azure", - "kubenet" - ], - "metadata": { - "description": "The network plugin type" - } - }, - "networkPluginMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Overlay" - ], - "metadata": { - "description": "The network plugin type" - } - }, - "networkPolicy": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "azure", - "calico", - "cilium" - ], - "metadata": { - "description": "The network policy to use." - } - }, - "ebpfDataplane": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "cilium" - ], - "metadata": { - "description": "Use Cilium dataplane (requires azure networkPlugin)" - } - }, - "podCidr": { - "type": "string", - "defaultValue": "192.168.0.0/16", - "minLength": 9, - "maxLength": 18, - "metadata": { - "description": "The address range to use for pods" - } - }, - "serviceCidr": { - "type": "string", - "defaultValue": "172.16.0.0/16", - "minLength": 9, - "maxLength": 18, - "metadata": { - "description": "The address range to use for services" - } - }, - "dockerBridgeCidr": { - "type": "string", - "defaultValue": "172.17.0.1/16", - "minLength": 9, - "maxLength": 18, - "metadata": { - "description": "The address range to use for the docker bridge" - } - }, - "dnsServiceIP": { - "type": "string", - "defaultValue": "172.16.0.10", - "minLength": 7, - "maxLength": 15, - "metadata": { - "description": "The IP address to reserve for DNS" - } - }, - "aksOutboundTrafficType": { - "type": "string", - "defaultValue": "loadBalancer", - "allowedValues": [ - "loadBalancer", - "natGateway", - "userDefinedRouting" - ], - "metadata": { - "description": "Outbound traffic type for the egress traffic of your cluster" - } - }, - "dnsPrefix": { - "type": "string", - "defaultValue": "[format('aks-{0}', resourceGroup().name)]", - "metadata": { - "description": "DNS prefix. Defaults to {resourceName}-dns" - } - }, - "natGwIpCount": { - "type": "int", - "defaultValue": 2, - "minValue": 1, - "maxValue": 16, - "metadata": { - "description": "The effective outbound IP resources of the cluster NAT gateway" - } - }, - "natGwIdleTimeout": { - "type": "int", - "defaultValue": 30, - "minValue": 4, - "maxValue": 120, - "metadata": { - "description": "Outbound flow idle timeout in minutes for NatGw" - } - }, - "cniDynamicIpAllocation": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Allocate pod ips dynamically" - } - }, - "custom_vnet": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Are you providing a custom VNET" - } - }, - "aksSubnetId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Full resource id path of an existing subnet to use for AKS" - } - }, - "aksPodSubnetId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Full resource id path of an existing pod subnet to use for AKS" - } - }, - "enablePrivateCluster": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable private cluster" - } - }, - "privateClusterDnsMethod": { - "type": "string", - "defaultValue": "system", - "allowedValues": [ - "system", - "none", - "privateDnsZone" - ], - "metadata": { - "description": "Private cluster dns advertisment method, leverages the dnsApiPrivateZoneId parameter" - } - }, - "dnsApiPrivateZoneId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The full Azure resource ID of the privatelink DNS zone to use for the AKS cluster API Server" + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "7144332081955097752" + } + }, + "definitions": { + "bladeSettings": { + "type": "object", + "properties": { + "sectionName": { + "type": "string", + "metadata": { + "description": "The name of the section name" + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "The display name of the section" + } + } } }, - "authorizedIPRanges": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "The IP addresses that are allowed to access the API server" + "manageSettings": { + "type": "object", + "properties": { + "machine": { + "$ref": "#/definitions/machineSettings", + "metadata": { + "description": "The settings for the virtual machine" + } + }, + "bastion": { + "$ref": "#/definitions/bastionSettings", + "metadata": { + "description": "The settings for the bastion" + } + } } }, - "azurepolicy": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "audit", - "deny" - ], - "metadata": { - "description": "Enable the Azure Policy addon" + "machineSettings": { + "type": "object", + "properties": { + "vmSize": { + "type": "string", + "metadata": { + "description": "The size of the virtual machine" + } + }, + "imagePublisher": { + "type": "string", + "metadata": { + "description": "The publisher of the image" + } + }, + "imageOffer": { + "type": "string", + "metadata": { + "description": "The offer of the image" + } + }, + "imageSku": { + "type": "string", + "metadata": { + "description": "The SKU of the image" + } + }, + "authenticationType": { + "type": "string", + "metadata": { + "description": "The authentication type of the virtual machine" + } + } } }, - "azurePolicyInitiative": { + "bastionSkuType": { "type": "string", - "defaultValue": "Baseline", "allowedValues": [ - "Baseline", - "Restricted" + "Basic", + "Standard" ] }, - "kedaEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enables Kubernetes Event-driven Autoscaling (KEDA)" - } - }, - "openServiceMeshEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enables Open Service Mesh" - } - }, - "workloadIdentityEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Installs Azure Workload Identity into the cluster" - } - }, - "defenderEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable Microsoft Defender for Containers (preview)" + "bastionSettings": { + "type": "object", + "properties": { + "skuName": { + "$ref": "#/definitions/bastionSkuType", + "metadata": { + "description": "The name of the SKU" + } + } } - }, - "keyvaultEnabled": { - "type": "bool", - "defaultValue": false, + } + }, + "parameters": { + "bladeConfig": { + "$ref": "#/definitions/bladeSettings", "metadata": { - "description": "Installs the AKS KV CSI provider" + "description": "The configuration for the blade section." } }, - "keyVaultAksCSIPollInterval": { + "location": { "type": "string", - "defaultValue": "2m", - "metadata": { - "description": "Rotation poll interval for the AKS KV CSI provider" - } - }, - "enable_aad": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable Azure AD integration on AKS" - } - }, - "enableAzureRBAC": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enable RBAC using AAD" - } - }, - "sgxPlugin": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enables SGX Confidential Compute plugin" - } - }, - "blobCSIDriver": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Enables the Blob CSI driver" - } - }, - "fileCSIDriver": { - "type": "bool", - "defaultValue": true, "metadata": { - "description": "Enables the File CSI driver" + "description": "The location of resources to deploy" } }, - "diskCSIDriver": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Enables the Disk CSI driver" - } - }, - "AksDisableLocalAccounts": { + "enableTelemetry": { "type": "bool", "defaultValue": false, "metadata": { - "description": "Disable local K8S accounts for AAD enabled clusters" + "description": "Feature Flag to Enable Telemetry" } }, - "oidcIssuer": { - "type": "bool", - "defaultValue": false, + "vmAdminUsername": { + "type": "string", "metadata": { - "description": "Configures the cluster as an OIDC issuer for use with Workload Identity" + "description": "Specifies the name of the administrator account of the virtual machine." } }, - "warIngressNginx": { - "type": "bool", - "defaultValue": false, + "vmAdminPasswordOrKey": { + "type": "securestring", "metadata": { - "description": "Enable Web App Routing" + "description": "Specifies the SSH Key or password for the virtual machine. SSH key is recommended." } }, - "enableImageCleaner": { + "enableBastion": { "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Specifies whether to enable ImageCleaner on AKS cluster. The default value is false." - } - }, - "imageCleanerIntervalHours": { - "type": "int", - "defaultValue": 24, - "metadata": { - "description": "Specifies whether ImageCleaner scanning interval in hours." - } - }, - "restrictionLevelNodeResourceGroup": { - "type": "string", - "defaultValue": "Unrestricted", - "allowedValues": [ - "ReadOnly", - "Unrestricted" - ], "metadata": { - "description": "The restriction level applied to the cluster node resource group" + "description": "Feature Flag to Enable Bastion" } }, - "serviceMeshProfile": { + "kvName": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "Istio" - ], "metadata": { - "description": "The service mesh profile to use" + "description": "The name of the Key Vault where the secret exists" } }, - "istioIngressGatewayMode": { + "vnetId": { "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "External", - "Internal", - "Both" - ], "metadata": { - "description": "The ingress gateway to use for the Istio service mesh" + "description": "The Id of the virtual network" } }, - "istioRevision": { + "vmSubnetId": { "type": "string", - "defaultValue": "asm-1-18" - }, - "automatedDeployment": { - "type": "bool", - "defaultValue": false, "metadata": { - "description": "If automated deployment, for the 3 automated user assignments, set Principal Type on each to \"ServicePrincipal\" rarter than \"User\"" + "description": "The Id of the subnet for the virtual machine" } }, - "adminPrincipalId": { + "workspaceName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "The principal ID to assign the AKS admin role." + "description": "The workspace name for diagnostics" } }, - "fluxGitOpsAddon": { - "type": "bool", - "defaultValue": false - }, - "daprAddon": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Add the Dapr extension" - } - }, - "daprAddonHA": { - "type": "bool", - "defaultValue": false, + "manageLayerConfig": { + "$ref": "#/definitions/manageSettings", "metadata": { - "description": "Enable high availability (HA) mode for the Dapr control plane" + "description": "The configuration for the manage section." } } }, - "variables": { - "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]", - "name": "[format('aks-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", - "serviceMeshProfileObj": { - "istio": { - "components": { - "ingressGateways": "[if(empty(parameters('istioIngressGatewayMode')), null(), union(if(equals(parameters('istioIngressGatewayMode'), 'Internal'), array(variables('ingressModes').internal), createArray()), if(equals(parameters('istioIngressGatewayMode'), 'External'), array(variables('ingressModes').external), createArray()), if(equals(parameters('istioIngressGatewayMode'), 'Both'), array(variables('ingressModes').internal), createArray()), if(equals(parameters('istioIngressGatewayMode'), 'Both'), array(variables('ingressModes').external), createArray())))]" - }, - "revisions": [ - "[parameters('istioRevision')]" - ] - }, - "mode": "Istio" - }, - "outboundTrafficType": "[if(equals(parameters('aksOutboundTrafficType'), 'natGateway'), if(parameters('custom_vnet'), 'userAssignedNATGateway', 'managedNATGateway'), parameters('aksOutboundTrafficType'))]", - "systemPoolPresets": { - "CostOptimised": { - "vmSize": "Standard_B4ms", - "minCount": 1, - "maxCount": 3, - "availabilityZones": [], - "osDiskType": "Managed", - "osDiskSize": 128, - "maxPods": 30 - }, - "Standard": { - "vmSize": "Standard_DS2_v2", - "minCount": 3, - "maxCount": 5, - "availabilityZones": [ - "1", - "2", - "3" - ], - "osDiskType": "Managed", - "osDiskSize": 128, - "maxPods": 30 - }, - "HighSpec": { - "vmSize": "Standard_D4s_v3", - "minCount": 3, - "maxCount": 10, - "availabilityZones": [ - "1", - "2", - "3" - ], - "osDiskType": "Managed", - "osDiskSize": 128, - "maxPods": 30 - } - }, - "systemPoolProfile": { - "name": "default", - "mode": "System", - "osType": "Linux", - "type": "VirtualMachineScaleSets", - "osDiskType": "[variables('systemPoolPresets')[parameters('clusterSize')].osDiskType]", - "osDiskSizeGB": "[variables('systemPoolPresets')[parameters('clusterSize')].osDiskSize]", - "vmSize": "[variables('systemPoolPresets')[parameters('clusterSize')].vmSize]", - "count": "[variables('systemPoolPresets')[parameters('clusterSize')].minCount]", - "minCount": "[variables('systemPoolPresets')[parameters('clusterSize')].minCount]", - "maxCount": "[variables('systemPoolPresets')[parameters('clusterSize')].maxCount]", - "availabilityZones": "[variables('systemPoolPresets')[parameters('clusterSize')].availabilityZones]", - "enableAutoScaling": true, - "maxPods": "[variables('systemPoolPresets')[parameters('clusterSize')].maxPods]", - "vnetSubnetID": "[if(not(empty(parameters('aksSubnetId'))), parameters('aksSubnetId'), null())]", - "podSubnetID": "[if(not(empty(parameters('aksPodSubnetId'))), parameters('aksPodSubnetId'), null())]", - "upgradeSettings": { - "maxSurge": "33%" - }, - "nodeTaints": [ - "[if(parameters('JustUseSystemPool'), '', 'CriticalAddonsOnly=true:NoSchedule')]" - ] - }, - "userPoolPresets": { - "CostOptimised": { - "vmSize": "Standard_B4ms", - "minCount": 1, - "maxCount": 3, - "availabilityZones": [], - "osDiskType": "Managed", - "osDiskSize": 128, - "maxPods": 30 - }, - "Standard": { - "vmSize": "Standard_E4s_v3", - "minCount": 3, - "maxCount": 15, - "availabilityZones": [ - "1", - "2", - "3" - ], - "osDiskType": "Managed", - "osDiskSize": 128, - "maxPods": 30 - }, - "HighSpec": { - "vmSize": "Standard_D8ds_v4", - "minCount": 8, - "maxCount": 20, - "availabilityZones": [ - "1", - "2", - "3" - ], - "osDiskType": "Ephemeral", - "osDiskSize": 0, - "maxPods": 30 - } - }, - "userPoolProfile": { - "name": "[parameters('nodePoolName')]", - "mode": "User", - "osType": "Linux", - "type": "VirtualMachineScaleSets", - "osDiskType": "[variables('userPoolPresets')[parameters('clusterSize')].osDiskType]", - "osDiskSizeGB": "[variables('userPoolPresets')[parameters('clusterSize')].osDiskSize]", - "vmSize": "[variables('userPoolPresets')[parameters('clusterSize')].vmSize]", - "count": "[variables('userPoolPresets')[parameters('clusterSize')].minCount]", - "minCount": "[variables('userPoolPresets')[parameters('clusterSize')].minCount]", - "maxCount": "[variables('userPoolPresets')[parameters('clusterSize')].maxCount]", - "availabilityZones": "[variables('userPoolPresets')[parameters('clusterSize')].availabilityZones]", - "enableAutoScaling": true, - "maxPods": "[variables('userPoolPresets')[parameters('clusterSize')].maxPods]", - "vnetSubnetID": "[if(not(empty(parameters('aksSubnetId'))), parameters('aksSubnetId'), null())]", - "podSubnetID": "[if(not(empty(parameters('aksPodSubnetId'))), parameters('aksPodSubnetId'), null())]", - "upgradeSettings": { - "maxSurge": "33%" - } + "resources": { + "existingVault": { + "condition": "[parameters('enableBastion')]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-07-01", + "name": "[parameters('kvName')]" }, - "agentPoolProfiles": "[if(parameters('JustUseSystemPool'), array(variables('systemPoolProfile')), concat(array(variables('systemPoolProfile')), array(variables('userPoolProfile'))))]", - "akssku": "[if(parameters('skuTierPaid'), 'Standard', 'Free')]", - "aks_addons": "[union(createObject('azurepolicy', createObject('config', createObject('version', if(not(empty(parameters('azurepolicy'))), 'v2', null())), 'enabled', not(empty(parameters('azurepolicy')))), 'azureKeyvaultSecretsProvider', createObject('config', createObject('enableSecretRotation', 'true', 'rotationPollInterval', parameters('keyVaultAksCSIPollInterval')), 'enabled', parameters('keyvaultEnabled')), 'openServiceMesh', createObject('enabled', parameters('openServiceMeshEnabled'), 'config', createObject()), 'ACCSGXDevicePlugin', createObject('enabled', parameters('sgxPlugin'), 'config', createObject())), if(not(empty(parameters('workspaceId'))), createObject('omsagent', createObject('enabled', not(empty(parameters('workspaceId'))), 'config', createObject('logAnalyticsWorkspaceResourceID', if(not(empty(parameters('workspaceId'))), parameters('workspaceId'), null())))), createObject()))]", - "aksPrivateDnsZone": "[if(equals(parameters('privateClusterDnsMethod'), 'privateDnsZone'), if(not(empty(parameters('dnsApiPrivateZoneId'))), parameters('dnsApiPrivateZoneId'), 'system'), parameters('privateClusterDnsMethod'))]", - "managedNATGatewayProfile": { - "natGatewayProfile": { - "managedOutboundIPProfile": { - "count": "[parameters('natGwIpCount')]" + "bastionHost": { + "condition": "[parameters('enableBastion')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-bastion', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" }, - "idleTimeoutInMinutes": "[parameters('natGwIdleTimeout')]" - } - }, - "azureDefenderSecurityProfile": { - "securityProfile": { - "defender": { - "logAnalyticsWorkspaceResourceId": "[parameters('workspaceId')]", - "securityMonitoring": { - "enabled": "[parameters('defenderEnabled')]" + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('bh-{0}{1}', replace(parameters('bladeConfig').sectionName, '-', ''), uniqueString(resourceGroup().id, parameters('bladeConfig').sectionName))]" + }, + "skuName": { + "value": "[parameters('manageLayerConfig').bastion.skuName]" + }, + "vNetId": { + "value": "[parameters('vnetId')]" + }, + "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.24.24.22086", + "templateHash": "18087298610689039063" + }, + "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": { + "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." + } + } + } + }, + "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." + } + }, + "vNetId": { + "type": "string", + "metadata": { + "description": "Required. Shared services Virtual Network resource identifier." + } + }, + "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": { + "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.network-bastionhost.{0}.{1}', replace('0.1.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" + } + } + } + } + }, + "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('vNetId')))), 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": { + "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')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/bastionHosts', 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": [ + "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": "[if(contains(parameters('publicIPAddressObject'), 'publicIPAddressVersion'), createObject('value', parameters('publicIPAddressObject').publicIPAddressVersion), createObject('value', 'IPv4'))]", + "publicIPAllocationMethod": "[if(contains(parameters('publicIPAddressObject'), 'publicIPAllocationMethod'), createObject('value', parameters('publicIPAddressObject').publicIPAllocationMethod), createObject('value', 'Static'))]", + "publicIpPrefixResourceId": "[if(contains(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId'), createObject('value', parameters('publicIPAddressObject').publicIPPrefixResourceId), createObject('value', ''))]", + "roleAssignments": "[if(contains(parameters('publicIPAddressObject'), 'roleAssignments'), createObject('value', parameters('publicIPAddressObject').roleAssignments), createObject('value', createArray()))]", + "skuName": "[if(contains(parameters('publicIPAddressObject'), 'skuName'), createObject('value', parameters('publicIPAddressObject').skuName), createObject('value', 'Standard'))]", + "skuTier": "[if(contains(parameters('publicIPAddressObject'), 'skuTier'), createObject('value', parameters('publicIPAddressObject').skuTier), createObject('value', 'Regional'))]", + "tags": { + "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" + }, + "zones": "[if(contains(parameters('publicIPAddressObject'), 'zones'), createObject('value', parameters('publicIPAddressObject').zones), createObject('value', 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.23.1.45101", + "templateHash": "3488076626994379707" + }, + "name": "Public IP Addresses", + "description": "This module deploys a Public IP Address.", + "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 + }, + "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 DDoS protection plan ID 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." + } + } + } + }, + "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." + } + } + } + }, + "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. 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", + "nullable": true, + "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": { + "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-publicipaddress.{0}.{1}', replace('0.2.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-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]", + "tier": "[parameters('skuTier')]" + }, + "zones": "[parameters('zones')]", + "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": [] + } + }, + "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(parameters('roleAssignments'), 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)]", + "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": [ + "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": { + "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')]", + "metrics": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics', 'timeGrain', null(), 'enabled', true())))]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs', 'enabled', true())))]", + "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": "[if(contains(reference('publicIpAddress'), 'ipAddress'), reference('publicIpAddress').ipAddress, '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('publicIpAddress', '2023-04-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]]" + } } } } }, - "aksProperties": "[union(createObject('kubernetesVersion', parameters('aksVersion'), 'enableRBAC', true(), 'dnsPrefix', parameters('dnsPrefix'), 'aadProfile', if(parameters('enable_aad'), createObject('managed', true(), 'enableAzureRBAC', parameters('enableAzureRBAC'), 'tenantID', parameters('aad_tenant_id'), 'adminGroupObjectIDs', if(empty(parameters('admin_ids')), null(), parameters('admin_ids'))), null()), 'apiServerAccessProfile', if(not(empty(parameters('authorizedIPRanges'))), createObject('authorizedIPRanges', parameters('authorizedIPRanges')), createObject('enablePrivateCluster', parameters('enablePrivateCluster'), 'privateDNSZone', if(parameters('enablePrivateCluster'), variables('aksPrivateDnsZone'), ''), 'enablePrivateClusterPublicFQDN', and(parameters('enablePrivateCluster'), equals(parameters('privateClusterDnsMethod'), 'none')))), 'agentPoolProfiles', variables('agentPoolProfiles'), 'workloadAutoScalerProfile', createObject('keda', createObject('enabled', parameters('kedaEnabled'))), 'networkProfile', createObject('loadBalancerSku', 'standard', 'networkPlugin', parameters('networkPlugin'), 'networkPolicy', parameters('networkPolicy'), 'networkPluginMode', if(equals(parameters('networkPlugin'), 'azure'), parameters('networkPluginMode'), ''), 'podCidr', if(or(or(equals(parameters('networkPlugin'), 'kubenet'), equals(parameters('networkPluginMode'), 'Overlay')), parameters('cniDynamicIpAllocation')), parameters('podCidr'), null()), 'serviceCidr', parameters('serviceCidr'), 'dnsServiceIP', parameters('dnsServiceIP'), 'dockerBridgeCidr', parameters('dockerBridgeCidr'), 'outboundType', variables('outboundTrafficType'), 'ebpfDataplane', if(equals(parameters('networkPlugin'), 'azure'), parameters('ebpfDataplane'), '')), 'disableLocalAccounts', and(parameters('AksDisableLocalAccounts'), parameters('enable_aad')), 'autoUpgradeProfile', createObject('upgradeChannel', parameters('upgradeChannel')), 'addonProfiles', variables('aks_addons'), 'autoScalerProfile', if(variables('autoScale'), parameters('AutoscaleProfile'), createObject()), 'oidcIssuerProfile', createObject('enabled', parameters('oidcIssuer')), 'securityProfile', createObject('workloadIdentity', createObject('enabled', parameters('workloadIdentityEnabled')), 'defender', createObject('logAnalyticsWorkspaceResourceId', if(parameters('defenderEnabled'), parameters('workspaceId'), null()), 'securityMonitoring', createObject('enabled', parameters('defenderEnabled'))), 'imageCleaner', createObject('enabled', parameters('enableImageCleaner'), 'intervalHours', parameters('imageCleanerIntervalHours'))), 'ingressProfile', createObject('webAppRouting', createObject('enabled', parameters('warIngressNginx'))), 'storageProfile', createObject('blobCSIDriver', createObject('enabled', parameters('blobCSIDriver')), 'diskCSIDriver', createObject('enabled', parameters('diskCSIDriver')), 'fileCSIDriver', createObject('enabled', parameters('fileCSIDriver'))), 'nodeResourceGroupProfile', createObject('restrictionLevel', parameters('restrictionLevelNodeResourceGroup'))), if(equals(variables('outboundTrafficType'), 'managedNATGateway'), variables('managedNATGatewayProfile'), createObject()), if(parameters('defenderEnabled'), variables('azureDefenderSecurityProfile'), createObject()), if(not(empty(parameters('managedNodeResourceGroup'))), createObject('nodeResourceGroup', parameters('managedNodeResourceGroup')), createObject()), if(not(empty(parameters('serviceMeshProfile'))), createObject('serviceMeshProfile', variables('serviceMeshProfileObj')), createObject()))]", - "ingressModes": { - "external": { - "enabled": true, - "mode": "External" - }, - "internal": { - "enabled": true, - "mode": "Internal" - } - }, - "policySetBaseline": "/providers/Microsoft.Authorization/policySetDefinitions/a8640138-9b0a-4a28-b8cb-1666c838647d", - "policySetRestrictive": "/providers/Microsoft.Authorization/policySetDefinitions/42b8ef37-b724-4e24-bbc8-7a7708edfe00", - "buildInAKSRBACClusterAdmin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b')]" - }, - "resources": [ - { - "type": "Microsoft.ContainerService/managedClusters", - "apiVersion": "2023-10-01", - "name": "[if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', parameters('identityId'))]": {} - } - }, - "properties": "[variables('aksProperties')]", - "sku": { - "name": "Base", - "tier": "[variables('akssku')]" - } - }, - { - "condition": "[not(empty(parameters('azurepolicy')))]", - "type": "Microsoft.Authorization/policyAssignments", - "apiVersion": "2023-04-01", - "name": "[format('{0}-{1}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')), parameters('azurePolicyInitiative'))]", - "location": "[parameters('location')]", + "virtualMachine": { + "condition": "[parameters('enableBastion')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-machine', parameters('bladeConfig').sectionName)]", "properties": { - "policyDefinitionId": "[if(equals(parameters('azurePolicyInitiative'), 'Baseline'), variables('policySetBaseline'), variables('policySetRestrictive'))]", + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", "parameters": { - "excludedNamespaces": { - "value": [ - "kube-system", - "gatekeeper-system", - "azure-arc", - "cluster-baseline-setting" - ] + "vmName": { + "value": "[format('vm-{0}{1}', replace(parameters('bladeConfig').sectionName, '-', ''), uniqueString(resourceGroup().id, parameters('bladeConfig').sectionName))]" }, - "effect": { - "value": "[parameters('azurepolicy')]" - } - }, - "metadata": { - "assignedBy": "Aks Construction" - }, - "displayName": "[format('Kubernetes cluster pod security {0} standards for Linux-based workloads', parameters('azurePolicyInitiative'))]", - "description": "As per: https://github.com/Azure/azure-policy/blob/master/built-in-policies/policySetDefinitions/Kubernetes/" - }, - "dependsOn": [ - "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" - ] - }, - { - "condition": "[and(parameters('enableAzureRBAC'), not(empty(parameters('adminPrincipalId'))))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", - "name": "[guid(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'aksadmin', variables('buildInAKSRBACClusterAdmin'))]", - "properties": { - "roleDefinitionId": "[variables('buildInAKSRBACClusterAdmin')]", - "principalType": "[if(parameters('automatedDeployment'), 'ServicePrincipal', 'User')]", - "principalId": "[parameters('adminPrincipalId')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" - ] - }, - { - "condition": "[parameters('fluxGitOpsAddon')]", - "type": "Microsoft.KubernetesConfiguration/extensions", - "apiVersion": "2023-05-01", - "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", - "name": "flux", - "properties": { - "extensionType": "microsoft.flux", - "autoUpgradeMinorVersion": true, - "configurationSettings": { - "multiTenancy.enforce": "false" - }, - "releaseTrain": "Stable", - "scope": { - "cluster": { - "releaseNamespace": "flux-system" - } - }, - "configurationProtectedSettings": {} - }, - "dependsOn": [ - "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", - "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'Microsoft.KubernetesConfiguration/extensions', 'dapr')]" - ] - }, - { - "condition": "[parameters('daprAddon')]", - "type": "Microsoft.KubernetesConfiguration/extensions", - "apiVersion": "2023-05-01", - "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", - "name": "dapr", - "properties": { - "extensionType": "Microsoft.Dapr", - "autoUpgradeMinorVersion": true, - "releaseTrain": "Stable", - "configurationSettings": { - "global.ha.enabled": "[format('{0}', parameters('daprAddonHA'))]" - }, - "scope": { - "cluster": { - "releaseNamespace": "dapr-system" - } + "vmSize": { + "value": "[parameters('manageLayerConfig').machine.vmSize]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } + }, + "vmSubnetId": { + "value": "[parameters('vmSubnetId')]" + }, + "vmAdminUsername": { + "value": "[parameters('vmAdminUsername')]" + }, + "vmAdminPasswordOrKey": "[if(empty(parameters('vmAdminPasswordOrKey')), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('kvName'))), 'secretName', 'PrivateLinkSSHKey-public')), createObject('value', parameters('vmAdminPasswordOrKey')))]", + "workspaceName": { + "value": "[parameters('workspaceName')]" + }, + "authenticationType": "[if(empty(parameters('vmAdminPasswordOrKey')), createObject('value', 'sshPublicKey'), createObject('value', 'password'))]" }, - "configurationProtectedSettings": {} + "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": "17291104921277876011" + } + }, + "parameters": { + "vmName": { + "type": "string", + "defaultValue": "simpleVM", + "metadata": { + "description": "Specifies the name of the virtual machine." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D2s_v3", + "metadata": { + "description": "Specifies the size of the virtual machine." + } + }, + "vmSubnetId": { + "type": "string", + "metadata": { + "description": "Specifies the resource id of the subnet hosting the virtual machine." + } + }, + "imagePublisher": { + "type": "string", + "defaultValue": "Canonical", + "metadata": { + "description": "Specifies the image publisher of the disk image used to create the virtual machine." + } + }, + "imageOffer": { + "type": "string", + "defaultValue": "0001-com-ubuntu-server-jammy", + "metadata": { + "description": "Specifies the offer of the platform image or marketplace image used to create the virtual machine." + } + }, + "imageSku": { + "type": "string", + "defaultValue": "22_04-lts-gen2", + "metadata": { + "description": "Specifies the Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version." + } + }, + "authenticationType": { + "type": "string", + "defaultValue": "password", + "allowedValues": [ + "sshPublicKey", + "password" + ], + "metadata": { + "description": "Specifies the type of authentication when accessing the Virtual Machine. SSH key is recommended." + } + }, + "vmAdminUsername": { + "type": "string", + "metadata": { + "description": "Specifies the name of the administrator account of the virtual machine." + } + }, + "vmAdminPasswordOrKey": { + "type": "securestring", + "metadata": { + "description": "Specifies the SSH Key or password for the virtual machine. SSH key is recommended." + } + }, + "diskStorageAccountType": { + "type": "string", + "defaultValue": "Standard_LRS", + "allowedValues": [ + "Premium_LRS", + "StandardSSD_LRS", + "Standard_LRS", + "UltraSSD_LRS" + ], + "metadata": { + "description": "Specifies the storage account type for OS and data disk." + } + }, + "numDataDisks": { + "type": "int", + "defaultValue": 0, + "minValue": 0, + "maxValue": 64, + "metadata": { + "description": "Specifies the number of data disks of the virtual machine." + } + }, + "osDiskSize": { + "type": "int", + "defaultValue": 30, + "metadata": { + "description": "Specifies the size in GB of the OS disk of the VM." + } + }, + "dataDiskSize": { + "type": "int", + "defaultValue": 50, + "metadata": { + "description": "Specifies the size in GB of the OS disk of the virtual machine." + } + }, + "dataDiskCaching": { + "type": "string", + "defaultValue": "ReadWrite", + "metadata": { + "description": "Specifies the caching requirements for the data disks." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Specifies the name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Specifies the location." + } + }, + "tags": { + "type": "object", + "metadata": { + "description": "Specifies the resource tags." + } + } + }, + "variables": { + "vmNicName": "[format('{0}Nic', parameters('vmName'))]", + "linuxConfiguration": { + "disablePasswordAuthentication": true, + "ssh": { + "publicKeys": [ + { + "path": "[format('/home/{0}/.ssh/authorized_keys', parameters('vmAdminUsername'))]", + "keyData": "[parameters('vmAdminPasswordOrKey')]" + } + ] + }, + "provisionVMAgent": true + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-06-01", + "name": "[variables('vmNicName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[parameters('vmSubnetId')]" + } + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "[parameters('vmName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('vmSize')]" + }, + "osProfile": { + "computerName": "[parameters('vmName')]", + "adminUsername": "[parameters('vmAdminUsername')]", + "adminPassword": "[parameters('vmAdminPasswordOrKey')]", + "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), null(), variables('linuxConfiguration'))]" + }, + "storageProfile": { + "copy": [ + { + "name": "dataDisks", + "count": "[length(range(0, parameters('numDataDisks')))]", + "input": { + "caching": "[parameters('dataDiskCaching')]", + "diskSizeGB": "[parameters('dataDiskSize')]", + "lun": "[range(0, parameters('numDataDisks'))[copyIndex('dataDisks')]]", + "name": "[format('{0}-DataDisk{1}', parameters('vmName'), range(0, parameters('numDataDisks'))[copyIndex('dataDisks')])]", + "createOption": "Empty", + "managedDisk": { + "storageAccountType": "[parameters('diskStorageAccountType')]" + } + } + } + ], + "imageReference": { + "publisher": "[parameters('imagePublisher')]", + "offer": "[parameters('imageOffer')]", + "sku": "[parameters('imageSku')]", + "version": "latest" + }, + "osDisk": { + "name": "[format('{0}_OSDisk', parameters('vmName'))]", + "caching": "ReadWrite", + "createOption": "FromImage", + "diskSizeGB": "[parameters('osDiskSize')]", + "managedDisk": { + "storageAccountType": "[parameters('diskStorageAccountType')]" + } + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNicName'))]" + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', variables('vmNicName'))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2023-09-01", + "name": "[format('{0}/{1}', parameters('vmName'), 'LogAnalytics')]", + "location": "[parameters('location')]", + "properties": { + "publisher": "Microsoft.EnterpriseCloud.Monitoring", + "type": "OmsAgentForLinux", + "typeHandlerVersion": "1.17", + "settings": { + "workspaceId": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '2022-10-01').customerId]", + "stopOnMultipleConnections": false + }, + "protectedSettings": { + "workspaceKey": "[listKeys(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '2022-10-01').primarySharedKey]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]" + ] + } + ] + } }, "dependsOn": [ - "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" + "existingVault" ] } - ], - "outputs": { - "aksClusterName": { - "type": "string", - "value": "[if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))]" - }, - "aksOidcIssuerUrl": { - "type": "string", - "value": "[if(parameters('oidcIssuer'), reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').oidcIssuerProfile.issuerURL, '')]" - }, - "userNodePoolName": { - "type": "string", - "value": "[parameters('nodePoolName')]" - }, - "systemNodePoolName": { - "type": "string", - "value": "[if(parameters('JustUseSystemPool'), parameters('nodePoolName'), 'npsystem')]" - }, - "aksPrivateDnsZone": { - "type": "string", - "value": "[variables('aksPrivateDnsZone')]" - }, - "privateFQDN": { - "type": "string", - "value": "[if(and(parameters('enablePrivateCluster'), not(equals(parameters('privateClusterDnsMethod'), 'none'))), reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').privateFQDN, '')]" - }, - "aksPrivateDnsZoneName": { - "type": "string", - "value": "[if(and(parameters('enablePrivateCluster'), not(equals(parameters('privateClusterDnsMethod'), 'none'))), join(skip(split(reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').privateFQDN, '.'), 1), '.'), '')]" - }, - "aksOidcFedIdentityProperties": { - "type": "object", - "metadata": { - "description": "This output can be directly leveraged when creating a ManagedId Federated Identity" - }, - "value": { - "issuer": "[if(parameters('oidcIssuer'), reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').oidcIssuerProfile.issuerURL, '')]", - "audiences": [ - "api://AzureADTokenExchange" - ], - "subject": "system:serviceaccount:ns:svcaccount" - } - }, - "aksNodeResourceGroup": { - "type": "string", - "metadata": { - "description": "The name of the managed resource group AKS uses" - }, - "value": "[reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').nodeResourceGroup]" - }, - "aksResourceId": { - "type": "string", - "metadata": { - "description": "The Azure resource id for the AKS cluster" - }, - "value": "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" - }, - "fluxReleaseNamespace": { - "type": "string", - "value": "[if(parameters('fluxGitOpsAddon'), reference(extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'Microsoft.KubernetesConfiguration/extensions', 'flux'), '2023-05-01').scope.cluster.releaseNamespace, '')]" - }, - "daprReleaseNamespace": { - "type": "string", - "value": "[if(parameters('daprAddon'), reference(extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'Microsoft.KubernetesConfiguration/extensions', 'dapr'), '2023-05-01').scope.cluster.releaseNamespace, '')]" - } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-log-analytics', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" + "commonBlade", + "logAnalytics", + "networkBlade" ] }, - { + "partitionBlade": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-pool1', variables('serviceLayerConfig').name)]", + "name": "partition-blade", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "AksName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksClusterName.value]" - }, - "PoolName": { - "value": "poolz1" - }, - "agentVMSize": { - "value": "[variables('elasticPoolPresets')[parameters('clusterSize')].vmSize]" - }, - "agentCount": { - "value": 2 - }, - "agentCountMax": { - "value": 4 - }, - "availabilityZones": { - "value": [ - "1" - ] - }, - "subnetId": "[if(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))))]", - "podSubnetId": "[if(and(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), parameters('enablePodSubnet')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('podSubnetName'))), createObject('value', ''))]", - "nodeTaints": { - "value": [ - "app=cluster:NoSchedule" - ] - }, - "nodeLabels": { + "bladeConfig": { "value": { - "app": "cluster" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "1717696639715253483" + "sectionName": "partitionblade", + "displayName": "Partition Resources" } }, - "parameters": { - "AksName": { - "type": "string" - }, - "PoolName": { - "type": "string" - }, - "availabilityZones": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "The zones to use for a node pool" - } - }, - "osDiskType": { - "type": "string", - "defaultValue": "Ephemeral", - "metadata": { - "description": "OS disk type" - } - }, - "agentVMSize": { - "type": "string", - "defaultValue": "Standard_DS3_v2", - "metadata": { - "description": "VM SKU" - } - }, - "osDiskSizeGB": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Disk size in GB" - } - }, - "agentCount": { - "type": "int", - "defaultValue": 3, - "metadata": { - "description": "The number of agents for the user node pool" - } - }, - "agentCountMax": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "The maximum number of nodes for the user node pool" - } - }, - "maxPods": { - "type": "int", - "defaultValue": 30, - "metadata": { - "description": "The maximum number of pods per node." - } - }, - "nodeTaints": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Any taints that should be applied to the node pool" - } - }, - "nodeLabels": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Any labels that should be applied to the node pool" - } - }, - "subnetId": { - "type": "string", - "metadata": { - "description": "The subnet the node pool will use" - } - }, - "podSubnetId": { - "type": "string", - "metadata": { - "description": "The subnet the pods will use" - } - }, - "osType": { - "type": "string", - "defaultValue": "Linux", - "allowedValues": [ - "Linux", - "Windows" - ], - "metadata": { - "description": "OS Type for the node pool" - } - } + "location": { + "value": "[parameters('location')]" }, - "variables": { - "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]" + "workspaceResourceId": { + "value": "[reference('logAnalytics').outputs.resourceId.value]" }, - "resources": [ - { - "type": "Microsoft.ContainerService/managedClusters/agentPools", - "apiVersion": "2023-10-02-preview", - "name": "[format('{0}/{1}', parameters('AksName'), parameters('PoolName'))]", - "properties": { - "mode": "User", - "vmSize": "[parameters('agentVMSize')]", - "count": "[parameters('agentCount')]", - "minCount": "[if(variables('autoScale'), parameters('agentCount'), null())]", - "maxCount": "[if(variables('autoScale'), parameters('agentCountMax'), null())]", - "enableAutoScaling": "[variables('autoScale')]", - "availabilityZones": "[if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null())]", - "osDiskType": "[parameters('osDiskType')]", - "osDiskSizeGB": "[parameters('osDiskSizeGB')]", - "osType": "[parameters('osType')]", - "maxPods": "[parameters('maxPods')]", - "type": "VirtualMachineScaleSets", - "vnetSubnetID": "[if(not(empty(parameters('subnetId'))), parameters('subnetId'), null())]", - "podSubnetID": "[if(not(empty(parameters('podSubnetId'))), parameters('podSubnetId'), null())]", - "upgradeSettings": { - "maxSurge": "33%" - }, - "nodeTaints": "[parameters('nodeTaints')]", - "nodeLabels": "[parameters('nodeLabels')]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-pool2', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "AksName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksClusterName.value]" + "kvName": { + "value": "[reference('commonBlade').outputs.keyvaultName.value]" }, - "PoolName": { - "value": "poolz2" + "subnetId": { + "value": "[reference('networkBlade').outputs.aksSubnetId.value]" }, - "agentVMSize": { - "value": "[variables('elasticPoolPresets')[parameters('clusterSize')].vmSize]" + "enableBlobPublicAccess": { + "value": "[parameters('enableBlobPublicAccess')]" }, - "agentCount": { - "value": 2 + "enablePrivateLink": { + "value": "[parameters('enablePrivateLink')]" }, - "agentCountMax": { - "value": 4 + "storageDNSZoneId": { + "value": "[reference('commonBlade').outputs.storageDNSZoneId.value]" }, - "availabilityZones": { - "value": [ - "2" - ] + "cosmosDNSZoneId": { + "value": "[reference('commonBlade').outputs.cosmosDNSZoneId.value]" }, - "subnetId": "[if(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))))]", - "podSubnetId": "[if(and(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), parameters('enablePodSubnet')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('podSubnetName'))), createObject('value', ''))]", - "nodeTaints": { - "value": [ - "app=cluster:NoSchedule" - ] + "partitionSize": { + "value": "[parameters('solutionTier')]" }, - "nodeLabels": { - "value": { - "app": "cluster" - } + "partitions": { + "value": "[parameters('partitions')]" } }, "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.24.24.22086", - "templateHash": "1717696639715253483" + "version": "0.25.53.49325", + "templateHash": "10141203071399513918" } }, - "parameters": { - "AksName": { - "type": "string" - }, - "PoolName": { - "type": "string" - }, - "availabilityZones": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "The zones to use for a node pool" - } - }, - "osDiskType": { - "type": "string", - "defaultValue": "Ephemeral", - "metadata": { - "description": "OS disk type" - } - }, - "agentVMSize": { - "type": "string", - "defaultValue": "Standard_DS3_v2", - "metadata": { - "description": "VM SKU" - } - }, - "osDiskSizeGB": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Disk size in GB" - } - }, - "agentCount": { - "type": "int", - "defaultValue": 3, - "metadata": { - "description": "The number of agents for the user node pool" - } - }, - "agentCountMax": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "The maximum number of nodes for the user node pool" - } - }, - "maxPods": { - "type": "int", - "defaultValue": 30, - "metadata": { - "description": "The maximum number of pods per node." - } - }, - "nodeTaints": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Any taints that should be applied to the node pool" - } - }, - "nodeLabels": { + "definitions": { + "bladeSettings": { "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Any labels that should be applied to the node pool" - } - }, - "subnetId": { - "type": "string", - "metadata": { - "description": "The subnet the node pool will use" - } - }, - "podSubnetId": { - "type": "string", - "metadata": { - "description": "The subnet the pods will use" - } - }, - "osType": { - "type": "string", - "defaultValue": "Linux", - "allowedValues": [ - "Linux", - "Windows" - ], - "metadata": { - "description": "OS Type for the node pool" - } - } - }, - "variables": { - "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]" - }, - "resources": [ - { - "type": "Microsoft.ContainerService/managedClusters/agentPools", - "apiVersion": "2023-10-02-preview", - "name": "[format('{0}/{1}', parameters('AksName'), parameters('PoolName'))]", "properties": { - "mode": "User", - "vmSize": "[parameters('agentVMSize')]", - "count": "[parameters('agentCount')]", - "minCount": "[if(variables('autoScale'), parameters('agentCount'), null())]", - "maxCount": "[if(variables('autoScale'), parameters('agentCountMax'), null())]", - "enableAutoScaling": "[variables('autoScale')]", - "availabilityZones": "[if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null())]", - "osDiskType": "[parameters('osDiskType')]", - "osDiskSizeGB": "[parameters('osDiskSizeGB')]", - "osType": "[parameters('osType')]", - "maxPods": "[parameters('maxPods')]", - "type": "VirtualMachineScaleSets", - "vnetSubnetID": "[if(not(empty(parameters('subnetId'))), parameters('subnetId'), null())]", - "podSubnetID": "[if(not(empty(parameters('podSubnetId'))), parameters('podSubnetId'), null())]", - "upgradeSettings": { - "maxSurge": "33%" + "sectionName": { + "type": "string", + "metadata": { + "description": "The name of the section name" + } }, - "nodeTaints": "[parameters('nodeTaints')]", - "nodeLabels": "[parameters('nodeLabels')]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-pool3', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "AksName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksClusterName.value]" - }, - "PoolName": { - "value": "poolz3" - }, - "agentVMSize": { - "value": "[variables('elasticPoolPresets')[parameters('clusterSize')].vmSize]" - }, - "agentCount": { - "value": 2 - }, - "agentCountMax": { - "value": 4 - }, - "availabilityZones": { - "value": [ - "3" - ] - }, - "subnetId": "[if(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('aksSubnetName'))))]", - "podSubnetId": "[if(and(not(equals(parameters('virtualNetworkNewOrExisting'), 'new')), parameters('enablePodSubnet')), createObject('value', format('{0}/subnets/{1}', createObject('new', if(equals(parameters('virtualNetworkNewOrExisting'), 'new'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name)), '2022-09-01').outputs.resourceId.value, null()), 'existing', resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))[parameters('virtualNetworkNewOrExisting')], parameters('podSubnetName'))), createObject('value', ''))]", - "nodeTaints": { - "value": [ - "app=cluster:NoSchedule" - ] - }, - "nodeLabels": { - "value": { - "app": "cluster" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "1717696639715253483" + "displayName": { + "type": "string", + "metadata": { + "description": "The display name of the section" + } + } + } } }, "parameters": { - "AksName": { - "type": "string" - }, - "PoolName": { - "type": "string" - }, - "availabilityZones": { - "type": "array", - "defaultValue": [], + "bladeConfig": { + "$ref": "#/definitions/bladeSettings", "metadata": { - "description": "The zones to use for a node pool" + "description": "The configuration for the blade section." } }, - "osDiskType": { + "location": { "type": "string", - "defaultValue": "Ephemeral", "metadata": { - "description": "OS disk type" + "description": "The location of resources to deploy" } }, - "agentVMSize": { - "type": "string", - "defaultValue": "Standard_DS3_v2", + "enableBlobPublicAccess": { + "type": "bool", "metadata": { - "description": "VM SKU" + "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." } }, - "osDiskSizeGB": { - "type": "int", - "defaultValue": 0, + "enablePrivateLink": { + "type": "bool", "metadata": { - "description": "Disk size in GB" + "description": "Feature Flag to Enable Private Link" } }, - "agentCount": { - "type": "int", - "defaultValue": 3, + "workspaceResourceId": { + "type": "string", "metadata": { - "description": "The number of agents for the user node pool" + "description": "The workspace resource Id for diagnostics" } }, - "agentCountMax": { - "type": "int", - "defaultValue": 0, + "subnetId": { + "type": "string", "metadata": { - "description": "The maximum number of nodes for the user node pool" + "description": "The subnet id for Private Endpoints" } }, - "maxPods": { - "type": "int", - "defaultValue": 30, + "cmekConfiguration": { + "type": "object", + "defaultValue": { + "kvUrl": "", + "keyName": "", + "identityId": "" + }, "metadata": { - "description": "The maximum number of pods per node." + "description": "Optional. Customer Managed Encryption Key." } }, - "nodeTaints": { - "type": "array", - "defaultValue": [], + "kvName": { + "type": "string", "metadata": { - "description": "Any taints that should be applied to the node pool" + "description": "The name of the Key Vault where the secret exists" } }, - "nodeLabels": { - "type": "object", - "defaultValue": {}, + "storageDNSZoneId": { + "type": "string", "metadata": { - "description": "Any labels that should be applied to the node pool" + "description": "Storage DNS Zone Id" } }, - "subnetId": { + "cosmosDNSZoneId": { "type": "string", "metadata": { - "description": "The subnet the node pool will use" + "description": "Cosmos DNS Zone Id" } }, - "podSubnetId": { + "partitionSize": { "type": "string", + "defaultValue": "CostOptimised", + "allowedValues": [ + "CostOptimised", + "Standard", + "HighSpec" + ], + "metadata": { + "description": "The Partition Size" + } + }, + "partitions": { + "type": "array", + "defaultValue": [ + { + "name": "opendes" + } + ], "metadata": { - "description": "The subnet the pods will use" + "description": "List of Data Partitions" + } + } + }, + "variables": { + "partitionLayerConfig": { + "secrets": { + "storageAccountName": "storage", + "storageAccountKey": "key", + "cosmosConnectionString": "cosmos-connection", + "cosmosEndpoint": "cosmos-endpoint", + "cosmosPrimaryKey": "cosmos-primary-key" + }, + "storage": { + "sku": "Standard_LRS", + "containers": [ + "legal-service-azure-configuration", + "osdu-wks-mappings", + "wdms-osdu", + "file-staging-area", + "file-persistent-area" + ] + }, + "database": { + "name": "osdu-db", + "CostOptimised": { + "throughput": 2000 + }, + "Standard": { + "throughput": 4000 + }, + "HighSpec": { + "throughput": 12000 + }, + "backup": "Continuous", + "containers": [ + { + "name": "LegalTag", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "StorageRecord", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "StorageSchema", + "kind": "Hash", + "paths": [ + "/kind" + ] + }, + { + "name": "TenantInfo", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "UserInfo", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "Authority", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "EntityType", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "SchemaInfo", + "kind": "Hash", + "paths": [ + "/partitionId" + ] + }, + { + "name": "Source", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "RegisterAction", + "kind": "Hash", + "paths": [ + "/dataPartitionId" + ] + }, + { + "name": "RegisterDdms", + "kind": "Hash", + "paths": [ + "/dataPartitionId" + ] + }, + { + "name": "RegisterSubscription", + "kind": "Hash", + "paths": [ + "/dataPartitionId" + ] + }, + { + "name": "IngestionStrategy", + "kind": "Hash", + "paths": [ + "/workflowType" + ] + }, + { + "name": "RelationshipStatus", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "MappingInfo", + "kind": "Hash", + "paths": [ + "/sourceSchemaKind" + ] + }, + { + "name": "FileLocationInfo", + "kind": "Hash", + "paths": [ + "/id" + ] + }, + { + "name": "WorkflowCustomOperatorInfo", + "kind": "Hash", + "paths": [ + "/operatorId" + ] + }, + { + "name": "WorkflowV2", + "kind": "Hash", + "paths": [ + "/partitionKey" + ] + }, + { + "name": "WorkflowRunV2", + "kind": "Hash", + "paths": [ + "/partitionKey" + ] + }, + { + "name": "WorkflowCustomOperatorV2", + "kind": "Hash", + "paths": [ + "/partitionKey" + ] + }, + { + "name": "WorkflowTasksSharingInfoV2", + "kind": "Hash", + "paths": [ + "/partitionKey" + ] + }, + { + "name": "Status", + "kind": "Hash", + "paths": [ + "/correlationId" + ] + }, + { + "name": "DataSetDetails", + "kind": "Hash", + "paths": [ + "/correlationId" + ] + } + ] + } + } + }, + "resources": { + "partitionStorage": { + "copy": { + "name": "partitionStorage", + "count": "[length(parameters('partitions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-azure-storage-{1}', parameters('bladeConfig').sectionName, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('sa{0}{1}', replace(format('data{0}{1}', copyIndex(), substring(uniqueString(parameters('partitions')[copyIndex()].name), 0, 6)), '-', ''), uniqueString(resourceGroup().id, format('data{0}{1}', copyIndex(), substring(uniqueString(parameters('partitions')[copyIndex()].name), 0, 6))))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]", + "partition": "[parameters('partitions')[copyIndex()].name]", + "purpose": "data" + } + }, + "diagnosticWorkspaceId": { + "value": "[parameters('workspaceResourceId')]" + }, + "diagnosticLogsRetentionInDays": { + "value": 0 + }, + "allowBlobPublicAccess": { + "value": "[parameters('enableBlobPublicAccess')]" + }, + "sku": { + "value": "[variables('partitionLayerConfig').storage.sku]" + }, + "containers": { + "value": "[concat(variables('partitionLayerConfig').storage.containers, createArray(parameters('partitions')[copyIndex()].name))]" + }, + "cmekConfiguration": { + "value": "[parameters('cmekConfiguration')]" + }, + "keyVaultName": { + "value": "[parameters('kvName')]" + }, + "storageAccountSecretName": { + "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.storageAccountName)]" + }, + "storageAccountKeySecretName": { + "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.storageAccountKey)]" + } + }, + "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": "10199713575446331736" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Used to name all resources" + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Resource Location." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags." + } + }, + "lock": { + "type": "string", + "defaultValue": "NotSpecified", + "allowedValues": [ + "CanNotDelete", + "NotSpecified", + "ReadOnly" + ], + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "sku": { + "type": "string", + "defaultValue": "Standard_LRS", + "allowedValues": [ + "Standard_LRS", + "Premium_LRS", + "Standard_GRS" + ], + "metadata": { + "description": "Specifies the storage account sku type." + } + }, + "accessTier": { + "type": "string", + "defaultValue": "Hot", + "allowedValues": [ + "Cool", + "Hot" + ], + "metadata": { + "description": "Specifies the storage account access tier." + } + }, + "containers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Storage Containers to be created." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Storage Tables to be created." + } + }, + "shares": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Storage Shares to be created." + } + }, + "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." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" + } + }, + "diagnosticWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "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." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "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." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "logsToEnable": { + "type": "array", + "defaultValue": [ + "StorageRead", + "StorageWrite", + "StorageDelete" + ], + "allowedValues": [ + "StorageRead", + "StorageWrite", + "StorageDelete" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed." + } + }, + "metricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], + "allowedValues": [ + "AllMetrics" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } + }, + "cmekConfiguration": { + "type": "object", + "defaultValue": { + "kvUrl": "", + "keyName": "", + "identityId": "" + }, + "metadata": { + "description": "Optional. Customer Managed Encryption Key." + } + }, + "deleteRetention": { + "type": "int", + "defaultValue": 0, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Amount of days the soft deleted data is stored and available for recovery. 0 is off." + } + }, + "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." + } + }, + "privateLinkSettings": { + "type": "object", + "defaultValue": { + "subnetId": "1", + "vnetId": "1" + }, + "metadata": { + "description": "Settings Required to Enable Private Link" + } + }, + "keyVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Key Vault Name to store secrets into" + } + }, + "storageAccountSecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account name into vault set the secret name." + } + }, + "storageAccountKeySecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account key into vault set the secret name." + } + }, + "storageAccountConnectionString": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account connectionstring into vault set the secret name." + } + }, + "basetime": { + "type": "string", + "defaultValue": "[utcNow('u')]", + "metadata": { + "description": "Optional: Current Date Time" + } + }, + "sasProperties": { + "type": "object", + "defaultValue": { + "signedServices": "b", + "signedPermission": "rl", + "signedExpiry": "[dateTimeAdd(parameters('basetime'), 'P1Y')]", + "signedResourceTypes": "sco", + "signedProtocol": "https" + }, + "metadata": { + "description": "Optional: Default SAS TOken Properties to download Blob." + } + }, + "saveToken": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional: To save storage account sas token into vault set the properties." + } + } + }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogs", + "count": "[length(parameters('logsToEnable'))]", + "input": { + "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('metricsToEnable'))]", + "input": { + "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "enableCMEK": "[if(and(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), not(empty(parameters('cmekConfiguration').identityId))), true(), false())]", + "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", + "privateEndpointName": "[format('{0}-PrivateEndpoint', parameters('name'))]", + "publicDNSZoneForwarder": "[format('blob.{0}', environment().suffixes.storage)]", + "privateDnsZoneName": "[format('privatelink.{0}', variables('publicDNSZoneForwarder'))]" + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "kind": "StorageV2", + "identity": "[if(variables('enableCMEK'), createObject('type', 'UserAssigned', 'userAssignedIdentities', createObject(format('{0}', parameters('cmekConfiguration').identityId), createObject())), null())]", + "properties": { + "accessTier": "[parameters('accessTier')]", + "minimumTlsVersion": "TLS1_2", + "encryption": "[if(variables('enableCMEK'), createObject('identity', createObject('userAssignedIdentity', parameters('cmekConfiguration').identityId), 'services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Keyvault', 'keyvaultproperties', createObject('keyname', parameters('cmekConfiguration').keyName, 'keyvaulturi', parameters('cmekConfiguration').kvUrl)), createObject('services', createObject('blob', createObject('enabled', true()), 'table', createObject('enabled', true()), 'file', createObject('enabled', true())), 'keySource', 'Microsoft.Storage'))]", + "allowBlobPublicAccess": "[parameters('allowBlobPublicAccess')]", + "networkAcls": "[if(variables('enablePrivateLink'), createObject('bypass', 'AzureServices', 'defaultAction', 'Deny'), createObject())]" + } + }, + { + "type": "Microsoft.Storage/storageAccounts/blobServices", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "properties": "[if(greater(parameters('deleteRetention'), 0), createObject('changeFeed', createObject('enabled', true()), 'restorePolicy', createObject('enabled', true(), 'days', 6), 'isVersioningEnabled', true(), 'deleteRetentionPolicy', createObject('enabled', true(), 'days', parameters('deleteRetention'))), createObject('deleteRetentionPolicy', createObject('enabled', false(), 'allowPermanentDelete', false())))]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/tableServices", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "properties": {}, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "type": "Microsoft.Storage/storageAccounts/fileServices", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "properties": { + "protocolSettings": {}, + "shareDeleteRetentionPolicy": { + "enabled": true, + "days": 7 + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "copy": { + "name": "storage_containers", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Storage/storageAccounts/blobServices/containers", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('containers')[copyIndex()])]", + "properties": { + "defaultEncryptionScope": "$account-encryption-key", + "denyEncryptionScopeOverride": false, + "publicAccess": "None" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" + ] + }, + { + "copy": { + "name": "storage_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Storage/storageAccounts/tableServices/tables", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('tables')[copyIndex()])]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/tableServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" + ] + }, + { + "copy": { + "name": "fileShare", + "count": "[length(parameters('shares'))]" + }, + "type": "Microsoft.Storage/storageAccounts/fileServices/shares", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}/{2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default', parameters('shares')[copyIndex()])]", + "properties": { + "shareQuota": "[parameters('shareQuota')]", + "rootSquash": "[if(equals(parameters('enabledProtocols'), 'NFS'), parameters('rootSquash'), null())]", + "enabledProtocols": "[parameters('enabledProtocols')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/fileServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]" + ] + }, + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/{1}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "name": "storage-diagnostics", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts/blobServices', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), 'default')]", + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('privateDnsZoneName')]", + "location": "global", + "properties": {} + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-01-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('location')]", + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]", + "groupIds": [ + "blob" + ] + } + } + ], + "subnet": { + "id": "[parameters('privateLinkSettings').subnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2022-01-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "dnsConfig", + "properties": { + "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]", + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', variables('privateDnsZoneName'), 'link_to_vnet')]", + "location": "global", + "properties": { + "registrationEnabled": false, + "virtualNetwork": { + "id": "[parameters('privateLinkSettings').vnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + ] + }, + { + "copy": { + "name": "storage_rbac", + "count": "[length(parameters('roleAssignments'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "18405904741015745823" + } + }, + "parameters": { + "description": { + "type": "string", + "defaultValue": "" + }, + "principalType": { + "type": "string", + "defaultValue": "" + }, + "roleDefinitionIdOrName": { + "type": "string" + }, + "resourceId": { + "type": "string" + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Avere Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a')]", + "Avere Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9')]", + "Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')]", + "Backup Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00c29273-979b-4161-815c-10b084fb9324')]", + "Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a795c7a0-d4a2-40c1-ae25-d81f01202912')]", + "Classic Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", + "Classic Storage Account Key Operator Service Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '')]", + "Data Box Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'add466c9-e687-43fc-8d98-dfcf8d720be5')]", + "Data Box Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '028f4ed7-e2a9-465e-a8f4-9c0ffdfdc027')]", + "Data Lake Analytics Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '47b7735b-770e-4598-a7da-8b91488b4c88')]", + "Elastic SAN Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '80dcbedb-47ef-405d-95bd-188a1b4ac406')]", + "Elastic SAN Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'af6a70f8-3c9f-4105-acf1-d719e9fca4ca')]", + "Elastic SAN Volume Group Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8281131-f312-4f34-8d98-ae12be9f0d23')]", + "Reader and Data Access": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349')]", + "Storage Account Backup Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "Storage Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e5e2a7ff-d759-4cd2-bb51-3152d37e2eb1')]", + "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', 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "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')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(last(split(parameters('resourceId'), '/')), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "principalType": "[if(not(empty(parameters('principalType'))), parameters('principalType'), null())]", + "delegatedManagedIdentityResourceId": "[if(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountSecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-name', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('storageAccountSecretName')]" + }, + "value": { + "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), 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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountKeySecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-key', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('storageAccountKeySecretName')]" + }, + "value": { + "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('storageAccountConnectionString'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-connectionstring', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('storageAccountConnectionString')]" + }, + "value": { + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), listKeys(resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))), '2022-05-01').keys[0].value, environment().suffixes.storage)]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), parameters('saveToken'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-sasToken', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[format('{0}-SAS', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + }, + "value": { + "value": "[listAccountSAS(if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')), '2022-05-01', parameters('sasProperties')).accountSasToken]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + ] + } + ], + "outputs": { + "id": { + "type": "string", + "metadata": { + "description": "The resource ID." + }, + "value": "[resourceId('Microsoft.Storage/storageAccounts', if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name')))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the resource." + }, + "value": "[if(greater(length(parameters('name')), 24), substring(parameters('name'), 0, 24), parameters('name'))]" + } + } + } } }, - "osType": { - "type": "string", - "defaultValue": "Linux", - "allowedValues": [ - "Linux", - "Windows" - ], - "metadata": { - "description": "OS Type for the node pool" - } - } - }, - "variables": { - "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]" - }, - "resources": [ - { - "type": "Microsoft.ContainerService/managedClusters/agentPools", - "apiVersion": "2023-10-02-preview", - "name": "[format('{0}/{1}', parameters('AksName'), parameters('PoolName'))]", + "partitionStorageEndpoint": { + "copy": { + "name": "partitionStorageEndpoint", + "count": "[length(parameters('partitions'))]" + }, + "condition": "[parameters('enablePrivateLink')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-azure-storage-endpoint-{1}', parameters('bladeConfig').sectionName, copyIndex())]", "properties": { - "mode": "User", - "vmSize": "[parameters('agentVMSize')]", - "count": "[parameters('agentCount')]", - "minCount": "[if(variables('autoScale'), parameters('agentCount'), null())]", - "maxCount": "[if(variables('autoScale'), parameters('agentCountMax'), null())]", - "enableAutoScaling": "[variables('autoScale')]", - "availabilityZones": "[if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null())]", - "osDiskType": "[parameters('osDiskType')]", - "osDiskSizeGB": "[parameters('osDiskSizeGB')]", - "osType": "[parameters('osType')]", - "maxPods": "[parameters('maxPods')]", - "type": "VirtualMachineScaleSets", - "vnetSubnetID": "[if(not(empty(parameters('subnetId'))), parameters('subnetId'), null())]", - "podSubnetID": "[if(not(empty(parameters('podSubnetId'))), parameters('podSubnetId'), null())]", - "upgradeSettings": { - "maxSurge": "33%" + "expressionEvaluationOptions": { + "scope": "inner" }, - "nodeTaints": "[parameters('nodeTaints')]", - "nodeLabels": "[parameters('nodeLabels')]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-virtual-network', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-user-managed-identity', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('id-{0}{1}', replace(variables('serviceLayerConfig').name, '-', ''), uniqueString(resourceGroup().id, variables('serviceLayerConfig').name))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "federatedIdentityCredentials": { - "value": [ - { - "audiences": [ - "api://AzureADTokenExchange" - ], - "issuer": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksOidcIssuerUrl.value]", - "name": "federated-ns_default", - "subject": "system:serviceaccount:default:workload-identity-sa" - } - ] - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "Managed Identity Operator", - "principalId": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.principalId.value]", - "principalType": "ServicePrincipal" - } - ] - }, - "tags": { - "value": { - "layer": "[variables('serviceLayerConfig').displayName]" - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "17425686371279834860" - }, - "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." + "mode": "Incremental", + "parameters": { + "resourceName": { + "value": "[reference(format('partitionStorage[{0}]', copyIndex())).outputs.name.value]" + }, + "subnetResourceId": { + "value": "[parameters('subnetId')]" + }, + "serviceResourceId": { + "value": "[reference(format('partitionStorage[{0}]', copyIndex())).outputs.id.value]" + }, + "groupIds": { + "value": [ + "blob" + ] + }, + "privateDnsZoneGroup": { + "value": { + "privateDNSResourceIds": [ + "[parameters('storageDNSZoneId')]" + ] + } } }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" + "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": "15826512194130576768" + } + }, + "parameters": { + "resourceName": { + "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." + } + }, + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the resource that needs to be connected to the network." + } + }, + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." + } + }, + "applicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "type": "array", + "defaultValue": [], + "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": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags." + } + }, + "lock": { + "type": "string", + "defaultValue": "NotSpecified", + "allowedValues": [ + "CanNotDelete", + "NotSpecified", + "ReadOnly" + ], + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "customDnsConfigs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + } + }, + "variables": { + "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", + "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", + "ipConfigurations": "[parameters('ipConfigurations')]", + "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[parameters('customDnsConfigs')]", + "privateLinkServiceConnections": [ + { + "name": "[parameters('resourceName')]", + "properties": { + "privateLinkServiceId": "[parameters('serviceResourceId')]", + "groupIds": "[parameters('groupIds')]" + } + } + ], + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDNSResourceIds": { + "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" + }, + "privateEndpointName": { + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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": "4839297301131483167" + } + }, + "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." + } + }, + "resourceName": { + "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": "2022-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('resourceName')]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(parameters('roleAssignments'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "10763501692852746164" + } + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + } ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" + } } } }, - "nullable": true + "dependsOn": [ + "[format('partitionStorage[{0}]', copyIndex())]", + "[format('partitionStorage[{0}]', copyIndex())]" + ] }, - "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'." - } + "partitionDb": { + "copy": { + "name": "partitionDb", + "count": "[length(parameters('partitions'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cosmos-db-{1}', parameters('bladeConfig').sectionName, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceName": { + "value": "[format('data{0}{1}', copyIndex(), substring(uniqueString(parameters('partitions')[copyIndex()].name), 0, 6))]" }, - "principalId": { - "type": "string", - "metadata": { - "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." - } + "resourceLocation": { + "value": "[parameters('location')]" }, - "principalType": { - "type": "string", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ], - "nullable": true, - "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]", + "partition": "[parameters('partitions')[copyIndex()].name]", + "purpose": "data" } }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the role assignment." + "diagnosticWorkspaceId": { + "value": "[parameters('workspaceResourceId')]" + }, + "diagnosticLogsRetentionInDays": { + "value": 0 + }, + "sqlDatabases": { + "value": [ + { + "name": "[variables('partitionLayerConfig').database.name]", + "containers": "[variables('partitionLayerConfig').database.containers]" + } + ] + }, + "maxThroughput": { + "value": "[variables('partitionLayerConfig').database[parameters('partitionSize')].throughput]" + }, + "backupPolicyType": { + "value": "[variables('partitionLayerConfig').database.backup]" + }, + "systemAssignedIdentity": { + "value": false + }, + "userAssignedIdentities": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', createObject(format('{0}', parameters('cmekConfiguration').identityId), createObject())), createObject('value', createObject()))]", + "defaultIdentity": "[if(not(empty(parameters('cmekConfiguration').identityId)), createObject('value', parameters('cmekConfiguration').identityId), createObject('value', ''))]", + "kvKeyUri": "[if(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), createObject('value', format('{0}/keys/{1}', parameters('cmekConfiguration').kvUrl, parameters('cmekConfiguration').keyName)), createObject('value', ''))]", + "keyVaultName": { + "value": "[parameters('kvName')]" + }, + "databaseEndpointSecretName": { + "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.cosmosEndpoint)]" + }, + "databasePrimaryKeySecretName": { + "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.cosmosPrimaryKey)]" + }, + "databaseConnectionStringSecretName": { + "value": "[format('{0}-{1}', parameters('partitions')[copyIndex()].name, variables('partitionLayerConfig').secrets.cosmosConnectionString)]" + } + }, + "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": "11940381066264844853" } }, - "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\"" + "parameters": { + "resourceName": { + "type": "string", + "minLength": 3, + "maxLength": 20, + "metadata": { + "description": "Used to name all resources" + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional: Resource Location." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags." + } + }, + "enableDeleteLock": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable lock to prevent accidental deletion" + } + }, + "multiwriteRegions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Locations enabled for the Cosmos DB account." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 4000, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + }, + "systemAssignedIdentity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedIdentities": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The ID(s) to assign to the resource." + } + }, + "defaultIdentity": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The default identity to be used." + } + }, + "databaseAccountOfferType": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Standard" + ], + "metadata": { + "description": "Optional. The offer type for the Cosmos DB database account." + } + }, + "defaultConsistencyLevel": { + "type": "string", + "defaultValue": "Session", + "allowedValues": [ + "Eventual", + "ConsistentPrefix", + "Session", + "BoundedStaleness", + "Strong" + ], + "metadata": { + "description": "Optional. The default consistency level of the Cosmos DB account." + } + }, + "automaticFailover": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable automatic failover for regions." + } + }, + "maxStalenessPrefix": { + "type": "int", + "defaultValue": 100000, + "minValue": 10, + "maxValue": 2147483647, + "metadata": { + "description": "Optional. Max stale requests. Required for BoundedStaleness. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000." + } + }, + "maxIntervalInSeconds": { + "type": "int", + "defaultValue": 300, + "minValue": 5, + "maxValue": 86400, + "metadata": { + "description": "Optional. Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400." + } + }, + "serverVersion": { + "type": "string", + "defaultValue": "4.2", + "allowedValues": [ + "3.2", + "3.6", + "4.0", + "4.2" + ], + "metadata": { + "description": "Optional. Specifies the MongoDB server version to use." + } + }, + "sqlDatabases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. SQL Databases configurations." + } + }, + "gremlinDatabases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Gremlin Databases configurations." + } + }, + "mongodbDatabases": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. MongoDB Databases configurations." + } + }, + "capabilitiesToAdd": { + "type": "array", + "defaultValue": [], + "allowedValues": [ + "EnableCassandra", + "EnableTable", + "EnableGremlin", + "EnableMongo", + "DisableRateLimitingResponses", + "EnableServerless" + ], + "metadata": { + "description": "Optional. List of Cosmos DB capabilities for the account." + } + }, + "backupPolicyType": { + "type": "string", + "defaultValue": "Periodic", + "allowedValues": [ + "Periodic", + "Continuous" + ], + "metadata": { + "description": "Optional. Describes the mode of backups." + } + }, + "backupPolicyContinuousTier": { + "type": "string", + "defaultValue": "Continuous30Days", + "allowedValues": [ + "Continuous30Days", + "Continuous7Days" + ], + "metadata": { + "description": "Optional. Configuration values for continuous mode backup." + } + }, + "backupIntervalInMinutes": { + "type": "int", + "defaultValue": 240, + "minValue": 60, + "maxValue": 1440, + "metadata": { + "description": "Optional. An integer representing the interval in minutes between two backups. Only applies to periodic backup type." + } + }, + "backupRetentionIntervalInHours": { + "type": "int", + "defaultValue": 8, + "minValue": 2, + "maxValue": 720, + "metadata": { + "description": "Optional. An integer representing the time (in hours) that each backup is retained. Only applies to periodic backup type." + } + }, + "backupStorageRedundancy": { + "type": "string", + "defaultValue": "Local", + "allowedValues": [ + "Geo", + "Local", + "Zone" + ], + "metadata": { + "description": "Optional. Enum to indicate type of backup residency. Only applies to periodic backup type." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" + } + }, + "diagnosticWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace." + } + }, + "diagnosticStorageAccountId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account." + } + }, + "diagnosticEventHubAuthorizationRuleId": { + "type": "string", + "defaultValue": "", + "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." + } + }, + "diagnosticEventHubName": { + "type": "string", + "defaultValue": "", + "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." + } + }, + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "logsToEnable": { + "type": "array", + "defaultValue": [ + "DataPlaneRequests", + "MongoRequests", + "QueryRuntimeStatistics", + "PartitionKeyStatistics", + "PartitionKeyRUConsumption", + "ControlPlaneRequests", + "CassandraRequests", + "GremlinRequests", + "TableApiRequests" + ], + "allowedValues": [ + "DataPlaneRequests", + "MongoRequests", + "QueryRuntimeStatistics", + "PartitionKeyStatistics", + "PartitionKeyRUConsumption", + "ControlPlaneRequests", + "CassandraRequests", + "GremlinRequests", + "TableApiRequests" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed." + } + }, + "metricsToEnable": { + "type": "array", + "defaultValue": [ + "Requests" + ], + "allowedValues": [ + "Requests" + ], + "metadata": { + "description": "Optional. The name of metrics that will be streamed." + } + }, + "kvKeyUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Customer Managed Encryption Key." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "privateLinkSettings": { + "type": "object", + "defaultValue": { + "subnetId": "1", + "vnetId": "1" + }, + "metadata": { + "description": "Settings Required to Enable Private Link" + } + }, + "keyVaultName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: Key Vault Name to store secrets into" + } + }, + "databaseEndpointSecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account name into vault set the secret hame." + } + }, + "databasePrimaryKeySecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account key into vault set the secret hame." + } + }, + "databaseConnectionStringSecretName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional: To save storage account connectionstring into vault set the secret hame." + } } }, - "conditionVersion": { - "type": "string", - "allowedValues": [ - "2.0" + "variables": { + "copy": [ + { + "name": "diagnosticsLogs", + "count": "[length(parameters('logsToEnable'))]", + "input": { + "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('metricsToEnable'))]", + "input": { + "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "databaseAccount_locations", + "count": "[length(parameters('multiwriteRegions'))]", + "input": { + "failoverPriority": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].failoverPriority]", + "isZoneRedundant": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].isZoneRedundant]", + "locationName": "[parameters('multiwriteRegions')[copyIndex('databaseAccount_locations')].locationName]" + } + }, + { + "name": "capabilities", + "count": "[length(parameters('capabilitiesToAdd'))]", + "input": { + "name": "[parameters('capabilitiesToAdd')[copyIndex('capabilities')]]" + } + } ], - "nullable": true, - "metadata": { - "description": "Optional. Version of the condition." - } + "name": "[format('dba-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", + "identityType": "[if(parameters('systemAssignedIdentity'), if(not(empty(parameters('userAssignedIdentities'))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", + "consistencyPolicy": { + "Eventual": { + "defaultConsistencyLevel": "Eventual" + }, + "ConsistentPrefix": { + "defaultConsistencyLevel": "ConsistentPrefix" + }, + "Session": { + "defaultConsistencyLevel": "Session" + }, + "BoundedStaleness": { + "defaultConsistencyLevel": "BoundedStaleness", + "maxStalenessPrefix": "[parameters('maxStalenessPrefix')]", + "maxIntervalInSeconds": "[parameters('maxIntervalInSeconds')]" + }, + "Strong": { + "defaultConsistencyLevel": "Strong" + } + }, + "kind": "[if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('gremlinDatabases')))), 'GlobalDocumentDB', if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'Parse'))]", + "backupPolicy": "[if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('type', parameters('backupPolicyType'), 'continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject('type', parameters('backupPolicyType'), 'periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))))]", + "databaseAccount_properties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType')), if(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', if(empty(parameters('multiwriteRegions')), false(), true()), 'locations', if(empty(parameters('multiwriteRegions')), createArray(createObject('failoverPriority', 0, 'isZoneRedundant', false(), 'locationName', parameters('resourceLocation'))), variables('databaseAccount_locations')), 'capabilities', variables('capabilities'), 'backupPolicy', variables('backupPolicy')), createObject()), if(not(empty(parameters('sqlDatabases'))), createObject('enableAutomaticFailover', parameters('automaticFailover'), 'AnalyticalStorageConfiguration', createObject('schemaType', 'WellDefined'), 'defaultIdentity', if(not(empty(parameters('defaultIdentity'))), format('UserAssignedIdentity={0}', parameters('defaultIdentity')), 'FirstPartyIdentity'), 'enablePartitionKeyMonitor', true(), 'enablePartitionMerge', false(), 'keyVaultKeyUri', if(not(empty(parameters('kvKeyUri'))), parameters('kvKeyUri'), json('null'))), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject('EnabledApiTypes', createArray('Sql'))))]", + "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", + "privateEndpointName": "[format('{0}-PrivateEndpoint', variables('name'))]", + "privateDNSZoneName": "privatelink.documents.azure.com" }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Resource Id of the delegated managed identity resource." + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts", + "apiVersion": "2022-08-15", + "name": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]", + "location": "[parameters('resourceLocation')]", + "tags": "[parameters('tags')]", + "identity": { + "type": "[variables('identityType')]", + "userAssignedIdentities": "[if(not(empty(parameters('userAssignedIdentities'))), parameters('userAssignedIdentities'), createObject())]" + }, + "kind": "[variables('kind')]", + "properties": "[variables('databaseAccount_properties')]" + }, + { + "condition": "[parameters('enableDeleteLock')]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "name": "[format('{0}-lock', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "properties": { + "level": "CanNotDelete" + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "name": "storage-diagnostics", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]", + "logAnalyticsDestinationType": "AzureDiagnostics" + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2021-02-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('resourceLocation')]", + "properties": { + "subnet": { + "id": "[parameters('privateLinkSettings').subnetId]" + }, + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]", + "groupIds": [ + "Sql" + ] + } + } + ], + "customDnsConfigs": [ + { + "fqdn": "[variables('privateDNSZoneName')]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', variables('privateDNSZoneName'), format('{0}-link', variables('privateDNSZoneName')))]", + "location": "global", + "properties": { + "registrationEnabled": false, + "virtualNetwork": { + "id": "[parameters('privateLinkSettings').vnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('privateDNSZoneName')]", + "location": "global" + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2022-01-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "config1", + "properties": { + "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZoneName'))]", + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] + }, + { + "copy": { + "name": "databaseAccount_sqlDatabases", + "count": "[length(parameters('sqlDatabases'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, parameters('sqlDatabases')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" + }, + "name": { + "value": "[parameters('sqlDatabases')[copyIndex()].name]" + }, + "throughput": { + "value": "[parameters('throughput')]" + }, + "maxThroughput": { + "value": "[parameters('maxThroughput')]" + }, + "containers": "[if(contains(parameters('sqlDatabases')[copyIndex()], 'containers'), createObject('value', parameters('sqlDatabases')[copyIndex()].containers), createObject('value', 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.25.53.49325", + "templateHash": "6008495898597068380" + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the SQL database ." + } + }, + "containers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of containers to deploy in the SQL database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the SQL database resource." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", + "resource": { + "id": "[parameters('name')]" + } + } + }, + { + "copy": { + "name": "container", + "count": "[length(parameters('containers'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-sql-{2}', deployment().name, parameters('name'), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "sqlDatabaseName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('containers')[copyIndex()].name]" + }, + "paths": { + "value": "[parameters('containers')[copyIndex()].paths]" + }, + "kind": { + "value": "[parameters('containers')[copyIndex()].kind]" + } + }, + "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": "8440494403171406302" + } + }, + "parameters": { + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "sqlDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the container." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the SQL Database resource." + } + }, + "paths": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of paths using which data within the container can be partitioned." + } + }, + "uniqueKeyPaths": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of unique key paths using which data within the container can be partitioned." + } + }, + "kind": { + "type": "string", + "defaultValue": "Hash", + "allowedValues": [ + "Hash", + "MultiHash", + "Range" + ], + "metadata": { + "description": "Optional. Indicates the kind of algorithm used for partitioning." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "partitionKey": { + "paths": "[parameters('paths')]", + "kind": "[parameters('kind')]" + }, + "uniqueKeyPolicy": "[if(empty(parameters('uniqueKeyPaths')), null(), createObject('uniqueKeys', createArray(createObject('paths', parameters('uniqueKeyPaths')))))]" + }, + "options": "[if(or(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), equals(parameters('throughput'), -1)), null(), createObject('throughput', parameters('throughput')))]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the container." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the container." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the container was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the SQL database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the SQL database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the SQL database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "copy": { + "name": "databaseAccount_gremlinDatabases", + "count": "[length(parameters('gremlinDatabases'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, parameters('gremlinDatabases')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "databaseAccountName": { + "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" + }, + "name": { + "value": "[parameters('gremlinDatabases')[copyIndex()].name]" + }, + "throughput": { + "value": "[parameters('throughput')]" + }, + "maxThroughput": { + "value": "[parameters('maxThroughput')]" + }, + "graphs": "[if(contains(parameters('gremlinDatabases')[copyIndex()], 'graphs'), createObject('value', parameters('gremlinDatabases')[copyIndex()].graphs), createObject('value', 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.25.53.49325", + "templateHash": "7475748416791876520" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Gremlin database." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the Gremlin database resource." + } + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." + } + }, + "graphs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of graphs to deploy in the Gremlin database." + } + }, + "maxThroughput": { + "type": "int", + "defaultValue": 400, + "metadata": { + "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." + } + }, + "throughput": { + "type": "int", + "defaultValue": -1, + "metadata": { + "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2022-08-15').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), -1), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', if(not(equals(parameters('throughput'), -1)), parameters('throughput'), null())))]", + "resource": { + "id": "[parameters('name')]" + } + } + }, + { + "copy": { + "name": "gremlinDatabase_gremlinGraphs", + "count": "[length(parameters('graphs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-graph-{2}', deployment().name, parameters('name'), parameters('graphs')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('graphs')[copyIndex()].name]" + }, + "gremlinDatabaseName": { + "value": "[parameters('name')]" + }, + "databaseAccountName": { + "value": "[parameters('databaseAccountName')]" + }, + "automaticIndexing": "[if(contains(parameters('graphs')[copyIndex()], 'automaticIndexing'), createObject('value', parameters('graphs')[copyIndex()].automaticIndexing), createObject('value', true()))]", + "partitionKeyPaths": "[if(not(empty(parameters('graphs')[copyIndex()].partitionKeyPaths)), createObject('value', parameters('graphs')[copyIndex()].partitionKeyPaths), createObject('value', 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.25.53.49325", + "templateHash": "6501375544323548839" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the graph." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the Gremlin graph resource." + } + }, + "databaseAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." + } + }, + "gremlinDatabaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." + } + }, + "automaticIndexing": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates if the indexing policy is automatic." + } + }, + "partitionKeyPaths": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of paths using which data within the container can be partitioned." + } + } + }, + "resources": [ + { + "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", + "apiVersion": "2022-08-15", + "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resource": { + "id": "[parameters('name')]", + "indexingPolicy": { + "automatic": "[parameters('automaticIndexing')]" + }, + "partitionKey": { + "paths": "[if(not(empty(parameters('partitionKeyPaths'))), parameters('partitionKeyPaths'), null())]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the graph." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the graph." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the graph was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Gremlin database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Gremlin database." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Gremlin database was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "copy": { + "name": "databaseaccount_rbac", + "count": "[length(parameters('roleAssignments'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "4583229135454794215" + } + }, + "parameters": { + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", + "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", + "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", + "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Managed Application Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')]", + "Managed Application Operator Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", + "Managed Applications Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Resource Policy Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.DocumentDB/databaseAccounts', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseEndpointSecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-name', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('databaseEndpointSecretName')]" + }, + "value": { + "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').documentEndpoint]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databasePrimaryKeySecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-key', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('databasePrimaryKeySecretName')]" + }, + "value": { + "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').primaryMasterKey]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] + }, + { + "condition": "[and(not(empty(parameters('keyVaultName'))), not(empty(parameters('databaseConnectionStringSecretName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secret-accountName', deployment().name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "name": { + "value": "[parameters('databaseConnectionStringSecretName')]" + }, + "value": { + "value": "[listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15').connectionStrings[0].connectionString]" + } + }, + "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": "45035995711227405" + } + }, + "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." + } + }, + "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." + } + } + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "properties": { + "value": "[parameters('value')]" + } + } + ], + "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": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + ] } - } - } - }, - "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": { - "type": "array", - "defaultValue": [], - "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 telemetry via a Globally Unique Identifier (GUID)." - } - } - }, - "variables": { - "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 (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.managedidentity-userassignedidentity.{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" + "name": { + "type": "string", + "metadata": { + "description": "The name of the database account." + }, + "value": "[if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the database account." + }, + "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the database account was created in." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[if(and(parameters('systemAssignedIdentity'), contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity, 'principalId')), reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').identity.principalId, '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', if(greater(length(variables('name')), 26), substring(variables('name'), 0, 26), variables('name'))), '2022-08-15', 'full').location]" } } } } }, - "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(parameters('roleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', 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": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { + "partitionDbEndpoint": { "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(parameters('federatedIdentityCredentials'))]" + "name": "partitionDbEndpoint", + "count": "[length(parameters('partitions'))]" }, + "condition": "[parameters('enablePrivateLink')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCredential-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "name": "[format('{0}-cosmos-db-endpoint-{1}', parameters('bladeConfig').sectionName, copyIndex())]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "[parameters('federatedIdentityCredentials')[copyIndex()].name]" + "resourceName": { + "value": "[reference(format('partitionDb[{0}]', copyIndex())).outputs.name.value]" }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" + "subnetResourceId": { + "value": "[parameters('subnetId')]" }, - "audiences": { - "value": "[parameters('federatedIdentityCredentials')[copyIndex()].audiences]" + "serviceResourceId": { + "value": "[reference(format('partitionDb[{0}]', copyIndex())).outputs.id.value]" }, - "issuer": { - "value": "[parameters('federatedIdentityCredentials')[copyIndex()].issuer]" + "groupIds": { + "value": [ + "sql" + ] }, - "subject": { - "value": "[parameters('federatedIdentityCredentials')[copyIndex()].subject]" + "privateDnsZoneGroup": { + "value": { + "privateDNSResourceIds": [ + "[parameters('cosmosDNSZoneId')]" + ] + } } }, "template": { @@ -21639,1255 +18996,3501 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "4906524580099045986" - }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential.", - "owner": "Azure/module-maintainers" + "version": "0.25.53.49325", + "templateHash": "15826512194130576768" + } }, "parameters": { - "userAssignedIdentityName": { + "resourceName": { + "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." + } + }, + "serviceResourceId": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "Required. Resource ID of the resource that needs to be connected to the network." } }, - "name": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. Subtype(s) of the connection to be created. The allowed values depend on the type serviceResourceId refers to." + } + }, + "applicationSecurityGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The name of the secret." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "audiences": { + "ipConfigurations": { "type": "array", + "defaultValue": [], "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." + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." } }, - "issuer": { + "privateDnsZoneGroup": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The private DNS zone group configuration used to associate the private endpoint with one or multiple private DNS zones. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "Optional. Location for all Resources." } }, - "subject": { + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "roleAssignments": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags." + } + }, + "lock": { "type": "string", + "defaultValue": "NotSpecified", + "allowedValues": [ + "CanNotDelete", + "NotSpecified", + "ReadOnly" + ], "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." + "description": "Optional. Specify the type of lock." + } + }, + "customDnsConfigs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." } } }, + "variables": { + "name": "[format('pep-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]" + }, "resources": [ { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2023-01-31", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" + "applicationSecurityGroups": "[parameters('applicationSecurityGroups')]", + "customNetworkInterfaceName": "[parameters('customNetworkInterfaceName')]", + "ipConfigurations": "[parameters('ipConfigurations')]", + "manualPrivateLinkServiceConnections": "[parameters('manualPrivateLinkServiceConnections')]", + "customDnsConfigs": "[parameters('customDnsConfigs')]", + "privateLinkServiceConnections": [ + { + "name": "[parameters('resourceName')]", + "properties": { + "privateLinkServiceId": "[parameters('serviceResourceId')]", + "groupIds": "[parameters('groupIds')]" + } + } + ], + "subnet": { + "id": "[parameters('subnetResourceId')]" + } } + }, + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}', deployment().name, if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateDNSResourceIds": { + "value": "[parameters('privateDnsZoneGroup').privateDNSResourceIds]" + }, + "privateEndpointName": { + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('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": "4839297301131483167" + } + }, + "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." + } + }, + "resourceName": { + "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": "2022-05-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('resourceName'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('resourceName')]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('resourceName'))]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] + }, + { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(parameters('roleAssignments'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principals": { + "value": "[parameters('roleAssignments')[copyIndex()].principals]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "condition": "[if(contains(parameters('roleAssignments')[copyIndex()], 'condition'), createObject('value', parameters('roleAssignments')[copyIndex()].condition), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + }, + "crossTenant": { + "value": "[parameters('crossTenant')]" + } + }, + "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": "10763501692852746164" + } + }, + "parameters": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "crossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if the module is used in a cross tenant scenario. If true, a resourceId must be provided in the role assignment's principal object." + } + }, + "principals": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to. A resourceId is required when used in a cross tenant scenario (i.e. crossTenant is true)" + } + } + }, + "variables": { + "builtInRoleNames": { + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" + } + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principals'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', last(split(parameters('resourceId'), '/'))), parameters('principals')[copyIndex()].id, parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principals')[copyIndex()].id]", + "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(parameters('crossTenant'), parameters('principals')[copyIndex()].resourceId, null())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" + ] } ], "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, "name": { "type": "string", "metadata": { - "description": "The name of the federated identity credential." + "description": "The name of the private endpoint." }, - "value": "[parameters('name')]" + "value": "[if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))]" }, - "resourceId": { + "id": { "type": "string", "metadata": { - "description": "The resource ID of the federated identity credential." + "description": "The resource ID of the private endpoint." }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "value": "[resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name')))]" }, - "resourceGroupName": { + "location": { "type": "string", "metadata": { - "description": "The name of the resource group the federated identity credential was created in." + "description": "The location the resource was deployed into." }, - "value": "[resourceGroup().name]" + "value": "[reference(resourceId('Microsoft.Network/privateEndpoints', if(greater(length(variables('name')), 24), substring(variables('name'), 0, 24), variables('name'))), '2022-05-01', 'full').location]" } } } }, "dependsOn": [ - "userAssignedIdentity" + "[format('partitionDb[{0}]', copyIndex())]", + "[format('partitionDb[{0}]', copyIndex())]" ] } }, "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." + "partitionStorageNames": { + "type": "array", + "items": { + "type": "string" }, - "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" + "copy": { + "count": "[length(parameters('partitions'))]", + "input": "[reference(format('partitionStorage[{0}]', copyIndex())).outputs.name.value]" + } } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" + "commonBlade", + "logAnalytics", + "networkBlade" ] }, - { + "serviceBlade": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-federated-cred-ns_dev-sample', variables('serviceLayerConfig').name)]", + "name": "service-blade", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "name": { - "value": "federated-ns_dev-sample" + "bladeConfig": { + "value": { + "sectionName": "serviceblade", + "displayName": "Service Resources" + } }, - "audiences": { - "value": [ - "api://AzureADTokenExchange" - ] + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "enableSoftwareLoad": { + "value": "[parameters('clusterSoftwareProperties').enable]" + }, + "workspaceResourceId": { + "value": "[reference('logAnalytics').outputs.resourceId.value]" + }, + "identityId": "[if(parameters('enableVnetInjection'), createObject('value', reference('networkBlade').outputs.networkConfiguration.value.identityId), createObject('value', reference('stampIdentity').outputs.resourceId.value))]", + "managedIdentityName": { + "value": "[reference('stampIdentity').outputs.name.value]" + }, + "kvName": { + "value": "[reference('commonBlade').outputs.keyvaultName.value]" + }, + "kvUri": { + "value": "[reference('commonBlade').outputs.keyvaultUri.value]" + }, + "storageName": { + "value": "[reference('commonBlade').outputs.storageAccountName.value]" + }, + "partitionStorageNames": { + "value": "[reference('partitionBlade').outputs.partitionStorageNames.value]" + }, + "aksSubnetId": { + "value": "[reference('networkBlade').outputs.aksSubnetId.value]" + }, + "podSubnetId": "[if(parameters('enablePodSubnet'), createObject('value', reference('networkBlade').outputs.podSubnetId.value), createObject('value', ''))]", + "clusterSize": { + "value": "[parameters('solutionTier')]" + }, + "clusterIngress": { + "value": "[parameters('clusterNetworkProperties').ingress]" + }, + "clusterAdminIds": { + "value": "[parameters('clusterAdminIds')]" }, - "issuer": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksOidcIssuerUrl.value]" + "serviceCidr": { + "value": "[parameters('clusterNetworkProperties').serviceCidr]" + }, + "dnsServiceIP": { + "value": "[parameters('clusterNetworkProperties').dnsServiceIP]" + }, + "dockerBridgeCidr": { + "value": "[parameters('clusterNetworkProperties').dockerBridgeCidr]" + }, + "networkPlugin": { + "value": "[parameters('clusterNetworkProperties').networkPlugin]" }, - "userAssignedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name)), '2022-09-01').outputs.name.value]" + "softwareBranch": { + "value": "[parameters('clusterSoftwareProperties').branch]" }, - "subject": { - "value": "system:serviceaccount:dev-sample:workload-identity-sa" + "softwareRepository": { + "value": "[parameters('clusterSoftwareProperties').repository]" } }, "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.24.24.22086", - "templateHash": "13076033972616288645" - }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential.", - "owner": "Azure/module-maintainers" + "version": "0.25.53.49325", + "templateHash": "8495879675301869583" + } + }, + "definitions": { + "bladeSettings": { + "type": "object", + "properties": { + "sectionName": { + "type": "string", + "metadata": { + "description": "The name of the section name" + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "The display name of the section" + } + } + } + } }, "parameters": { - "userAssignedIdentityName": { - "type": "string", + "bladeConfig": { + "$ref": "#/definitions/bladeSettings", "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "The configuration for the blade section." } }, - "name": { + "location": { "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." + "description": "The location of resources to deploy" } }, - "issuer": { - "type": "string", + "enableTelemetry": { + "type": "bool", "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "Feature Flag to Enable Telemetry" } }, - "subject": { + "workspaceResourceId": { "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')]" + "description": "The workspace resource Id for diagnostics" } - } - ], - "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'))]" + "networkPlugin": { + "type": "string" }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the federated identity credential was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-federated-cred-ns_config-maps', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "federated-ns_azappconfig-system" - }, - "audiences": { - "value": [ - "api://AzureADTokenExchange" - ] - }, - "issuer": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksOidcIssuerUrl.value]" - }, - "userAssignedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "subject": { - "value": "system:serviceaccount:azappconfig-system:az-appconfig-k8s-provider" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "13076033972616288645" + "clusterSize": { + "type": "string" }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "userAssignedIdentityName": { + "kvName": { "type": "string", "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + "description": "The name of the Key Vault where the secret exists" } }, - "name": { + "kvUri": { "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." + "description": "The Uri of the Key Vault where the secret exists" } }, - "issuer": { + "storageName": { "type": "string", "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + "description": "The name of the Storage Account" } }, - "subject": { + "softwareRepository": { "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')]" + "description": "Software GIT Repository URL" } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the federated identity credential." - }, - "value": "[parameters('name')]" }, - "resourceId": { + "softwareBranch": { "type": "string", "metadata": { - "description": "The resource ID of the federated identity credential." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + "description": "Software GIT Repository Branch" + } }, - "resourceGroupName": { + "clusterIngress": { "type": "string", - "metadata": { - "description": "The name of the resource group the federated identity credential was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-federated-cred-ns_dev-sample', variables('serviceLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-user-managed-identity-rbac', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "identityprincipalId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name)), '2022-09-01').outputs.principalId.value]" - }, - "kvName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "storageName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "6554602783679072342" - } - }, - "parameters": { - "identityprincipalId": { - "type": "string" + "allowedValues": [ + "Internal", + "External", + "Both" + ], + "metadata": { + "description": "The Cluster Ingress Mode" + } }, - "kvName": { - "type": "string", - "defaultValue": "", + "clusterAdminIds": { + "type": "array", "metadata": { - "description": "The name of the Azure Key Vault" + "description": "Optional: Specify the AD Users and/or Groups that can manage the cluster." } }, - "storageName": { + "serviceCidr": { "type": "string", - "defaultValue": "", + "minLength": 9, + "maxLength": 18, "metadata": { - "description": "The name of the Azure Storage Account" - } - } - }, - "variables": { - "keyVaultSecretsUser": "[resourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "storageFileDataSmbShareReader": "[resourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "storageBlobContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "storageTableContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]" - }, - "resources": [ - { - "condition": "[not(equals(parameters('kvName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), variables('keyVaultSecretsUser'))]", - "properties": { - "roleDefinitionId": "[variables('keyVaultSecretsUser')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" + "description": "The address range to use for services" } }, - { - "condition": "[not(equals(parameters('storageName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageFileDataSmbShareReader'))]", - "properties": { - "roleDefinitionId": "[variables('storageFileDataSmbShareReader')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" + "dockerBridgeCidr": { + "type": "string", + "minLength": 9, + "maxLength": 18, + "metadata": { + "description": "The address range to use for the docker bridge" } }, - { - "condition": "[not(equals(parameters('storageName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageBlobContributor'))]", - "properties": { - "roleDefinitionId": "[variables('storageBlobContributor')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" + "dnsServiceIP": { + "type": "string", + "minLength": 7, + "maxLength": 15, + "metadata": { + "description": "The IP address to reserve for DNS" } }, - { - "condition": "[not(equals(parameters('storageName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageTableContributor'))]", - "properties": { - "roleDefinitionId": "[variables('storageTableContributor')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage', variables('commonLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-federated-cred-ns_config-maps', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]" - ] - }, - { - "copy": { - "name": "appRoleAssignments2", - "count": "[length(parameters('partitions'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-user-managed-identity-rbac-{1}', variables('serviceLayerConfig').name, parameters('partitions')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "identityprincipalId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name)), '2022-09-01').outputs.principalId.value]" - }, - "storageName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex())), '2022-09-01').outputs.name.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "6554602783679072342" - } - }, - "parameters": { - "identityprincipalId": { + "aksSubnetId": { "type": "string" }, - "kvName": { + "podSubnetId": { + "type": "string", + "defaultValue": "" + }, + "managedIdentityName": { "type": "string", - "defaultValue": "", "metadata": { - "description": "The name of the Azure Key Vault" + "description": "The managed identity name for deployment scripts" } }, - "storageName": { + "identityId": { "type": "string", - "defaultValue": "", "metadata": { - "description": "The name of the Azure Storage Account" + "description": "The user managed identity for the cluster." + } + }, + "partitionStorageNames": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The name of the partition storage accounts" + } + }, + "enableSoftwareLoad": { + "type": "bool", + "metadata": { + "description": "Feature Flag to Load Software." } } }, "variables": { - "keyVaultSecretsUser": "[resourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", - "storageFileDataSmbShareReader": "[resourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", - "storageBlobContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "storageTableContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]" - }, - "resources": [ - { - "condition": "[not(equals(parameters('kvName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), variables('keyVaultSecretsUser'))]", - "properties": { - "roleDefinitionId": "[variables('keyVaultSecretsUser')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" + "serviceLayerConfig": { + "cluster": { + "aksVersion": "1.28", + "meshVersion": "asm-1-18", + "networkPlugin": "[parameters('networkPlugin')]" + }, + "gitops": { + "name": "flux-system", + "url": "[if(equals(parameters('softwareRepository'), ''), 'https://github.com/azure/osdu-developer', parameters('softwareRepository'))]", + "branch": "[if(equals(parameters('softwareBranch'), ''), 'main', parameters('softwareBranch'))]", + "components": "./stamp/components", + "applications": "./stamp/applications" + }, + "imageList": { + "None": [], + "M22": [ + "community.opengroup.org:5555/osdu/platform/system/partition/partition-v0-24-0:latest", + "community.opengroup.org:5555/osdu/platform/security-and-compliance/entitlements/entitlements-v0-24-0:latest", + "community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/legal-v0-24-0:latest", + "community.opengroup.org:5555/osdu/platform/system/schema-service/schema-service-release-0-24:latest", + "community.opengroup.org:5555/osdu/platform/system/storage/storage-v0-24-0:latest", + "community.opengroup.org:5555/osdu/platform/system/file/file-v0-24-0:latest", + "community.opengroup.org:5555/osdu/platform/system/indexer-service/indexer-service-v0-24-0:latest", + "community.opengroup.org:5555/osdu/platform/system/search-service/search-service-v0-24-0:latest" + ] } }, - { - "condition": "[not(equals(parameters('storageName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageFileDataSmbShareReader'))]", - "properties": { - "roleDefinitionId": "[variables('storageFileDataSmbShareReader')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" + "elasticPoolPresets": { + "CostOptimised": { + "vmSize": "Standard_DS3_v2" + }, + "Standard": { + "vmSize": "Standard_DS4_v2" + }, + "HighSpec": { + "vmSize": "Standard_DS5_v2" } }, - { - "condition": "[not(equals(parameters('storageName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageBlobContributor'))]", + "appSettings": [ + { + "name": "Settings:Message", + "value": "Hello from App Configuration", + "contentType": "text/plain", + "label": "configmap-devsample" + }, + { + "name": "Settings:StorageAccountName", + "value": "[parameters('partitionStorageNames')[0]]", + "contentType": "text/plain", + "label": "configmap-devsample" + } + ], + "configMaps": { + "appConfigTemplate": "values.yaml: |\n serviceAccount:\n create: false\n name: \"workload-identity-sa\"\n azure:\n tenantId: {0}\n clientId: {1}\n configEndpoint: {2}\n keyvaultUri: {3}\n keyvaultName: {4}\n " + } + }, + "resources": { + "cluster": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-aks-cluster', parameters('bladeConfig').sectionName)]", "properties": { - "roleDefinitionId": "[variables('storageBlobContributor')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "resourceName": { + "value": "[parameters('bladeConfig').sectionName]" + }, + "location": { + "value": "[parameters('location')]" + }, + "aksVersion": { + "value": "[variables('serviceLayerConfig').cluster.aksVersion]" + }, + "aad_tenant_id": { + "value": "[subscription().tenantId]" + }, + "clusterSize": { + "value": "[parameters('clusterSize')]" + }, + "networkPlugin": { + "value": "[variables('serviceLayerConfig').cluster.networkPlugin]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } + }, + "aksSubnetId": { + "value": "[parameters('aksSubnetId')]" + }, + "aksPodSubnetId": "[if(equals(parameters('podSubnetId'), ''), createObject('value', null()), createObject('value', parameters('podSubnetId')))]", + "identityId": { + "value": "[parameters('identityId')]" + }, + "workspaceId": { + "value": "[parameters('workspaceResourceId')]" + }, + "serviceCidr": { + "value": "[parameters('serviceCidr')]" + }, + "dnsServiceIP": { + "value": "[parameters('dnsServiceIP')]" + }, + "dockerBridgeCidr": { + "value": "[parameters('dockerBridgeCidr')]" + }, + "serviceMeshProfile": { + "value": "Istio" + }, + "istioRevision": { + "value": "[variables('serviceLayerConfig').cluster.meshVersion]" + }, + "istioIngressGatewayMode": { + "value": "[parameters('clusterIngress')]" + }, + "enable_aad": "[if(equals(empty(parameters('clusterAdminIds')), true()), createObject('value', false()), createObject('value', true()))]", + "admin_ids": { + "value": "[parameters('clusterAdminIds')]" + }, + "workloadIdentityEnabled": { + "value": true + }, + "oidcIssuer": { + "value": true + }, + "keyvaultEnabled": { + "value": true + }, + "fluxGitOpsAddon": { + "value": true + }, + "enableImageCleaner": { + "value": true + }, + "fileCSIDriver": { + "value": true + }, + "blobCSIDriver": { + "value": true + }, + "azurepolicy": { + "value": "audit" + } + }, + "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": "13760300592188278271" + } + }, + "parameters": { + "resourceName": { + "type": "string", + "minLength": 1, + "maxLength": 63, + "metadata": { + "description": "Used to name all resources" + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Specify the location of the AKS cluster." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Tags." + } + }, + "aad_tenant_id": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The ID of the Azure AD tenant" + } + }, + "admin_ids": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The ID of the Azure AD tenant" + } + }, + "skuTierPaid": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Use the paid sku for SLA rather than SLO" + } + }, + "aksVersion": { + "type": "string", + "defaultValue": "1.28", + "metadata": { + "description": "Kubernetes Version" + } + }, + "upgradeChannel": { + "type": "string", + "defaultValue": "stable", + "allowedValues": [ + "none", + "patch", + "stable", + "rapid", + "node-image" + ], + "metadata": { + "description": "AKS upgrade channel" + } + }, + "managedNodeResourceGroup": { + "type": "string", + "defaultValue": "", + "maxLength": 80, + "metadata": { + "description": "The name of the NEW resource group to create the AKS cluster managed resources in" + } + }, + "clusterSize": { + "type": "string", + "defaultValue": "CostOptimised", + "allowedValues": [ + "CostOptimised", + "Standard", + "HighSpec", + "Custom" + ], + "metadata": { + "description": "The System Pool Preset sizing" + } + }, + "AutoscaleProfile": { + "type": "object", + "defaultValue": { + "balance-similar-node-groups": "true", + "expander": "random", + "max-empty-bulk-delete": "10", + "max-graceful-termination-sec": "600", + "max-node-provision-time": "15m", + "max-total-unready-percentage": "45", + "new-pod-scale-up-delay": "0s", + "ok-total-unready-count": "3", + "scale-down-delay-after-add": "10m", + "scale-down-delay-after-delete": "20s", + "scale-down-delay-after-failure": "3m", + "scale-down-unneeded-time": "10m", + "scale-down-unready-time": "20m", + "scale-down-utilization-threshold": "0.5", + "scan-interval": "10s", + "skip-nodes-with-local-storage": "true", + "skip-nodes-with-system-pods": "true" + }, + "metadata": { + "description": "The System Pool Preset sizing" + } + }, + "agentCount": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "The number of agents for the user node pool" + } + }, + "agentCountMax": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "The maximum number of nodes for the user node pool" + } + }, + "nodePoolName": { + "type": "string", + "defaultValue": "internal", + "minLength": 3, + "maxLength": 12, + "metadata": { + "description": "Name for user node pool" + } + }, + "JustUseSystemPool": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Only use the system node pool" + } + }, + "workspaceId": { + "type": "string", + "metadata": { + "description": "Specify the Log Analytics Workspace Id to use for monitoring." + } + }, + "identityId": { + "type": "string", + "metadata": { + "description": "Specify the User Managed Identity Resource Id." + } + }, + "networkPlugin": { + "type": "string", + "defaultValue": "azure", + "allowedValues": [ + "azure", + "kubenet" + ], + "metadata": { + "description": "The network plugin type" + } + }, + "networkPluginMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Overlay" + ], + "metadata": { + "description": "The network plugin type" + } + }, + "networkPolicy": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "azure", + "calico", + "cilium" + ], + "metadata": { + "description": "The network policy to use." + } + }, + "ebpfDataplane": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "cilium" + ], + "metadata": { + "description": "Use Cilium dataplane (requires azure networkPlugin)" + } + }, + "podCidr": { + "type": "string", + "defaultValue": "192.168.0.0/16", + "minLength": 9, + "maxLength": 18, + "metadata": { + "description": "The address range to use for pods" + } + }, + "serviceCidr": { + "type": "string", + "defaultValue": "172.16.0.0/16", + "minLength": 9, + "maxLength": 18, + "metadata": { + "description": "The address range to use for services" + } + }, + "dockerBridgeCidr": { + "type": "string", + "defaultValue": "172.17.0.1/16", + "minLength": 9, + "maxLength": 18, + "metadata": { + "description": "The address range to use for the docker bridge" + } + }, + "dnsServiceIP": { + "type": "string", + "defaultValue": "172.16.0.10", + "minLength": 7, + "maxLength": 15, + "metadata": { + "description": "The IP address to reserve for DNS" + } + }, + "aksOutboundTrafficType": { + "type": "string", + "defaultValue": "loadBalancer", + "allowedValues": [ + "loadBalancer", + "natGateway", + "userDefinedRouting" + ], + "metadata": { + "description": "Outbound traffic type for the egress traffic of your cluster" + } + }, + "dnsPrefix": { + "type": "string", + "defaultValue": "[format('aks-{0}', resourceGroup().name)]", + "metadata": { + "description": "DNS prefix. Defaults to {resourceName}-dns" + } + }, + "natGwIpCount": { + "type": "int", + "defaultValue": 2, + "minValue": 1, + "maxValue": 16, + "metadata": { + "description": "The effective outbound IP resources of the cluster NAT gateway" + } + }, + "natGwIdleTimeout": { + "type": "int", + "defaultValue": 30, + "minValue": 4, + "maxValue": 120, + "metadata": { + "description": "Outbound flow idle timeout in minutes for NatGw" + } + }, + "cniDynamicIpAllocation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Allocate pod ips dynamically" + } + }, + "custom_vnet": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Are you providing a custom VNET" + } + }, + "aksSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Full resource id path of an existing subnet to use for AKS" + } + }, + "aksPodSubnetId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Full resource id path of an existing pod subnet to use for AKS" + } + }, + "enablePrivateCluster": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable private cluster" + } + }, + "privateClusterDnsMethod": { + "type": "string", + "defaultValue": "system", + "allowedValues": [ + "system", + "none", + "privateDnsZone" + ], + "metadata": { + "description": "Private cluster dns advertisment method, leverages the dnsApiPrivateZoneId parameter" + } + }, + "dnsApiPrivateZoneId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The full Azure resource ID of the privatelink DNS zone to use for the AKS cluster API Server" + } + }, + "authorizedIPRanges": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The IP addresses that are allowed to access the API server" + } + }, + "azurepolicy": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "audit", + "deny" + ], + "metadata": { + "description": "Enable the Azure Policy addon" + } + }, + "azurePolicyInitiative": { + "type": "string", + "defaultValue": "Baseline", + "allowedValues": [ + "Baseline", + "Restricted" + ] + }, + "kedaEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enables Kubernetes Event-driven Autoscaling (KEDA)" + } + }, + "openServiceMeshEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enables Open Service Mesh" + } + }, + "workloadIdentityEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Installs Azure Workload Identity into the cluster" + } + }, + "defenderEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable Microsoft Defender for Containers (preview)" + } + }, + "keyvaultEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Installs the AKS KV CSI provider" + } + }, + "keyVaultAksCSIPollInterval": { + "type": "string", + "defaultValue": "2m", + "metadata": { + "description": "Rotation poll interval for the AKS KV CSI provider" + } + }, + "enable_aad": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable Azure AD integration on AKS" + } + }, + "enableAzureRBAC": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable RBAC using AAD" + } + }, + "sgxPlugin": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enables SGX Confidential Compute plugin" + } + }, + "blobCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enables the Blob CSI driver" + } + }, + "fileCSIDriver": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enables the File CSI driver" + } + }, + "diskCSIDriver": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Enables the Disk CSI driver" + } + }, + "AksDisableLocalAccounts": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Disable local K8S accounts for AAD enabled clusters" + } + }, + "oidcIssuer": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Configures the cluster as an OIDC issuer for use with Workload Identity" + } + }, + "warIngressNginx": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable Web App Routing" + } + }, + "enableImageCleaner": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Specifies whether to enable ImageCleaner on AKS cluster. The default value is false." + } + }, + "imageCleanerIntervalHours": { + "type": "int", + "defaultValue": 24, + "metadata": { + "description": "Specifies whether ImageCleaner scanning interval in hours." + } + }, + "restrictionLevelNodeResourceGroup": { + "type": "string", + "defaultValue": "Unrestricted", + "allowedValues": [ + "ReadOnly", + "Unrestricted" + ], + "metadata": { + "description": "The restriction level applied to the cluster node resource group" + } + }, + "serviceMeshProfile": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Istio" + ], + "metadata": { + "description": "The service mesh profile to use" + } + }, + "istioIngressGatewayMode": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "External", + "Internal", + "Both" + ], + "metadata": { + "description": "The ingress gateway to use for the Istio service mesh" + } + }, + "istioRevision": { + "type": "string", + "defaultValue": "asm-1-18" + }, + "automatedDeployment": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "If automated deployment, for the 3 automated user assignments, set Principal Type on each to \"ServicePrincipal\" rarter than \"User\"" + } + }, + "adminPrincipalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The principal ID to assign the AKS admin role." + } + }, + "fluxGitOpsAddon": { + "type": "bool", + "defaultValue": false + }, + "daprAddon": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Add the Dapr extension" + } + }, + "daprAddonHA": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Enable high availability (HA) mode for the Dapr control plane" + } + } + }, + "variables": { + "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]", + "name": "[format('aks-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", + "serviceMeshProfileObj": { + "istio": { + "components": { + "ingressGateways": "[if(empty(parameters('istioIngressGatewayMode')), null(), union(if(equals(parameters('istioIngressGatewayMode'), 'Internal'), array(variables('ingressModes').internal), createArray()), if(equals(parameters('istioIngressGatewayMode'), 'External'), array(variables('ingressModes').external), createArray()), if(equals(parameters('istioIngressGatewayMode'), 'Both'), array(variables('ingressModes').internal), createArray()), if(equals(parameters('istioIngressGatewayMode'), 'Both'), array(variables('ingressModes').external), createArray())))]" + }, + "revisions": [ + "[parameters('istioRevision')]" + ] + }, + "mode": "Istio" + }, + "outboundTrafficType": "[if(equals(parameters('aksOutboundTrafficType'), 'natGateway'), if(parameters('custom_vnet'), 'userAssignedNATGateway', 'managedNATGateway'), parameters('aksOutboundTrafficType'))]", + "systemPoolPresets": { + "CostOptimised": { + "vmSize": "Standard_B4ms", + "minCount": 1, + "maxCount": 3, + "availabilityZones": [], + "osDiskType": "Managed", + "osDiskSize": 128, + "maxPods": 30 + }, + "Standard": { + "vmSize": "Standard_DS2_v2", + "minCount": 3, + "maxCount": 5, + "availabilityZones": [ + "1", + "2", + "3" + ], + "osDiskType": "Managed", + "osDiskSize": 128, + "maxPods": 30 + }, + "HighSpec": { + "vmSize": "Standard_D4s_v3", + "minCount": 3, + "maxCount": 10, + "availabilityZones": [ + "1", + "2", + "3" + ], + "osDiskType": "Managed", + "osDiskSize": 128, + "maxPods": 30 + } + }, + "systemPoolProfile": { + "name": "default", + "mode": "System", + "osType": "Linux", + "type": "VirtualMachineScaleSets", + "osDiskType": "[variables('systemPoolPresets')[parameters('clusterSize')].osDiskType]", + "osDiskSizeGB": "[variables('systemPoolPresets')[parameters('clusterSize')].osDiskSize]", + "vmSize": "[variables('systemPoolPresets')[parameters('clusterSize')].vmSize]", + "count": "[variables('systemPoolPresets')[parameters('clusterSize')].minCount]", + "minCount": "[variables('systemPoolPresets')[parameters('clusterSize')].minCount]", + "maxCount": "[variables('systemPoolPresets')[parameters('clusterSize')].maxCount]", + "availabilityZones": "[variables('systemPoolPresets')[parameters('clusterSize')].availabilityZones]", + "enableAutoScaling": true, + "maxPods": "[variables('systemPoolPresets')[parameters('clusterSize')].maxPods]", + "vnetSubnetID": "[if(not(empty(parameters('aksSubnetId'))), parameters('aksSubnetId'), null())]", + "podSubnetID": "[if(not(empty(parameters('aksPodSubnetId'))), parameters('aksPodSubnetId'), null())]", + "upgradeSettings": { + "maxSurge": "33%" + }, + "nodeTaints": [ + "[if(parameters('JustUseSystemPool'), '', 'CriticalAddonsOnly=true:NoSchedule')]" + ] + }, + "userPoolPresets": { + "CostOptimised": { + "vmSize": "Standard_B4ms", + "minCount": 1, + "maxCount": 3, + "availabilityZones": [], + "osDiskType": "Managed", + "osDiskSize": 128, + "maxPods": 30 + }, + "Standard": { + "vmSize": "Standard_E4s_v3", + "minCount": 3, + "maxCount": 15, + "availabilityZones": [ + "1", + "2", + "3" + ], + "osDiskType": "Managed", + "osDiskSize": 128, + "maxPods": 30 + }, + "HighSpec": { + "vmSize": "Standard_D8ds_v4", + "minCount": 8, + "maxCount": 20, + "availabilityZones": [ + "1", + "2", + "3" + ], + "osDiskType": "Ephemeral", + "osDiskSize": 0, + "maxPods": 30 + } + }, + "userPoolProfile": { + "name": "[parameters('nodePoolName')]", + "mode": "User", + "osType": "Linux", + "type": "VirtualMachineScaleSets", + "osDiskType": "[variables('userPoolPresets')[parameters('clusterSize')].osDiskType]", + "osDiskSizeGB": "[variables('userPoolPresets')[parameters('clusterSize')].osDiskSize]", + "vmSize": "[variables('userPoolPresets')[parameters('clusterSize')].vmSize]", + "count": "[variables('userPoolPresets')[parameters('clusterSize')].minCount]", + "minCount": "[variables('userPoolPresets')[parameters('clusterSize')].minCount]", + "maxCount": "[variables('userPoolPresets')[parameters('clusterSize')].maxCount]", + "availabilityZones": "[variables('userPoolPresets')[parameters('clusterSize')].availabilityZones]", + "enableAutoScaling": true, + "maxPods": "[variables('userPoolPresets')[parameters('clusterSize')].maxPods]", + "vnetSubnetID": "[if(not(empty(parameters('aksSubnetId'))), parameters('aksSubnetId'), null())]", + "podSubnetID": "[if(not(empty(parameters('aksPodSubnetId'))), parameters('aksPodSubnetId'), null())]", + "upgradeSettings": { + "maxSurge": "33%" + } + }, + "agentPoolProfiles": "[if(parameters('JustUseSystemPool'), array(variables('systemPoolProfile')), concat(array(variables('systemPoolProfile')), array(variables('userPoolProfile'))))]", + "akssku": "[if(parameters('skuTierPaid'), 'Standard', 'Free')]", + "aks_addons": "[union(createObject('azurepolicy', createObject('config', createObject('version', if(not(empty(parameters('azurepolicy'))), 'v2', null())), 'enabled', not(empty(parameters('azurepolicy')))), 'azureKeyvaultSecretsProvider', createObject('config', createObject('enableSecretRotation', 'true', 'rotationPollInterval', parameters('keyVaultAksCSIPollInterval')), 'enabled', parameters('keyvaultEnabled')), 'openServiceMesh', createObject('enabled', parameters('openServiceMeshEnabled'), 'config', createObject()), 'ACCSGXDevicePlugin', createObject('enabled', parameters('sgxPlugin'), 'config', createObject())), if(not(empty(parameters('workspaceId'))), createObject('omsagent', createObject('enabled', not(empty(parameters('workspaceId'))), 'config', createObject('logAnalyticsWorkspaceResourceID', if(not(empty(parameters('workspaceId'))), parameters('workspaceId'), null())))), createObject()))]", + "aksPrivateDnsZone": "[if(equals(parameters('privateClusterDnsMethod'), 'privateDnsZone'), if(not(empty(parameters('dnsApiPrivateZoneId'))), parameters('dnsApiPrivateZoneId'), 'system'), parameters('privateClusterDnsMethod'))]", + "managedNATGatewayProfile": { + "natGatewayProfile": { + "managedOutboundIPProfile": { + "count": "[parameters('natGwIpCount')]" + }, + "idleTimeoutInMinutes": "[parameters('natGwIdleTimeout')]" + } + }, + "azureDefenderSecurityProfile": { + "securityProfile": { + "defender": { + "logAnalyticsWorkspaceResourceId": "[parameters('workspaceId')]", + "securityMonitoring": { + "enabled": "[parameters('defenderEnabled')]" + } + } + } + }, + "aksProperties": "[union(createObject('kubernetesVersion', parameters('aksVersion'), 'enableRBAC', true(), 'dnsPrefix', parameters('dnsPrefix'), 'aadProfile', if(parameters('enable_aad'), createObject('managed', true(), 'enableAzureRBAC', parameters('enableAzureRBAC'), 'tenantID', parameters('aad_tenant_id'), 'adminGroupObjectIDs', if(empty(parameters('admin_ids')), null(), parameters('admin_ids'))), null()), 'apiServerAccessProfile', if(not(empty(parameters('authorizedIPRanges'))), createObject('authorizedIPRanges', parameters('authorizedIPRanges')), createObject('enablePrivateCluster', parameters('enablePrivateCluster'), 'privateDNSZone', if(parameters('enablePrivateCluster'), variables('aksPrivateDnsZone'), ''), 'enablePrivateClusterPublicFQDN', and(parameters('enablePrivateCluster'), equals(parameters('privateClusterDnsMethod'), 'none')))), 'agentPoolProfiles', variables('agentPoolProfiles'), 'workloadAutoScalerProfile', createObject('keda', createObject('enabled', parameters('kedaEnabled'))), 'networkProfile', createObject('loadBalancerSku', 'standard', 'networkPlugin', parameters('networkPlugin'), 'networkPolicy', parameters('networkPolicy'), 'networkPluginMode', if(equals(parameters('networkPlugin'), 'azure'), parameters('networkPluginMode'), ''), 'podCidr', if(or(or(equals(parameters('networkPlugin'), 'kubenet'), equals(parameters('networkPluginMode'), 'Overlay')), parameters('cniDynamicIpAllocation')), parameters('podCidr'), null()), 'serviceCidr', parameters('serviceCidr'), 'dnsServiceIP', parameters('dnsServiceIP'), 'dockerBridgeCidr', parameters('dockerBridgeCidr'), 'outboundType', variables('outboundTrafficType'), 'ebpfDataplane', if(equals(parameters('networkPlugin'), 'azure'), parameters('ebpfDataplane'), '')), 'disableLocalAccounts', and(parameters('AksDisableLocalAccounts'), parameters('enable_aad')), 'autoUpgradeProfile', createObject('upgradeChannel', parameters('upgradeChannel')), 'addonProfiles', variables('aks_addons'), 'autoScalerProfile', if(variables('autoScale'), parameters('AutoscaleProfile'), createObject()), 'oidcIssuerProfile', createObject('enabled', parameters('oidcIssuer')), 'securityProfile', createObject('workloadIdentity', createObject('enabled', parameters('workloadIdentityEnabled')), 'defender', createObject('logAnalyticsWorkspaceResourceId', if(parameters('defenderEnabled'), parameters('workspaceId'), null()), 'securityMonitoring', createObject('enabled', parameters('defenderEnabled'))), 'imageCleaner', createObject('enabled', parameters('enableImageCleaner'), 'intervalHours', parameters('imageCleanerIntervalHours'))), 'ingressProfile', createObject('webAppRouting', createObject('enabled', parameters('warIngressNginx'))), 'storageProfile', createObject('blobCSIDriver', createObject('enabled', parameters('blobCSIDriver')), 'diskCSIDriver', createObject('enabled', parameters('diskCSIDriver')), 'fileCSIDriver', createObject('enabled', parameters('fileCSIDriver'))), 'nodeResourceGroupProfile', createObject('restrictionLevel', parameters('restrictionLevelNodeResourceGroup'))), if(equals(variables('outboundTrafficType'), 'managedNATGateway'), variables('managedNATGatewayProfile'), createObject()), if(parameters('defenderEnabled'), variables('azureDefenderSecurityProfile'), createObject()), if(not(empty(parameters('managedNodeResourceGroup'))), createObject('nodeResourceGroup', parameters('managedNodeResourceGroup')), createObject()), if(not(empty(parameters('serviceMeshProfile'))), createObject('serviceMeshProfile', variables('serviceMeshProfileObj')), createObject()))]", + "ingressModes": { + "external": { + "enabled": true, + "mode": "External" + }, + "internal": { + "enabled": true, + "mode": "Internal" + } + }, + "policySetBaseline": "/providers/Microsoft.Authorization/policySetDefinitions/a8640138-9b0a-4a28-b8cb-1666c838647d", + "policySetRestrictive": "/providers/Microsoft.Authorization/policySetDefinitions/42b8ef37-b724-4e24-bbc8-7a7708edfe00", + "buildInAKSRBACClusterAdmin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b')]" + }, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2023-10-01", + "name": "[if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('identityId'))]": {} + } + }, + "properties": "[variables('aksProperties')]", + "sku": { + "name": "Base", + "tier": "[variables('akssku')]" + } + }, + { + "condition": "[not(empty(parameters('azurepolicy')))]", + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2023-04-01", + "name": "[format('{0}-{1}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')), parameters('azurePolicyInitiative'))]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[if(equals(parameters('azurePolicyInitiative'), 'Baseline'), variables('policySetBaseline'), variables('policySetRestrictive'))]", + "parameters": { + "excludedNamespaces": { + "value": [ + "kube-system", + "gatekeeper-system", + "azure-arc", + "cluster-baseline-setting" + ] + }, + "effect": { + "value": "[parameters('azurepolicy')]" + } + }, + "metadata": { + "assignedBy": "Aks Construction" + }, + "displayName": "[format('Kubernetes cluster pod security {0} standards for Linux-based workloads', parameters('azurePolicyInitiative'))]", + "description": "As per: https://github.com/Azure/azure-policy/blob/master/built-in-policies/policySetDefinitions/Kubernetes/" + }, + "dependsOn": [ + "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" + ] + }, + { + "condition": "[and(parameters('enableAzureRBAC'), not(empty(parameters('adminPrincipalId'))))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", + "name": "[guid(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'aksadmin', variables('buildInAKSRBACClusterAdmin'))]", + "properties": { + "roleDefinitionId": "[variables('buildInAKSRBACClusterAdmin')]", + "principalType": "[if(parameters('automatedDeployment'), 'ServicePrincipal', 'User')]", + "principalId": "[parameters('adminPrincipalId')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" + ] + }, + { + "condition": "[parameters('fluxGitOpsAddon')]", + "type": "Microsoft.KubernetesConfiguration/extensions", + "apiVersion": "2023-05-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", + "name": "flux", + "properties": { + "extensionType": "microsoft.flux", + "autoUpgradeMinorVersion": true, + "configurationSettings": { + "multiTenancy.enforce": "false" + }, + "releaseTrain": "Stable", + "scope": { + "cluster": { + "releaseNamespace": "flux-system" + } + }, + "configurationProtectedSettings": {} + }, + "dependsOn": [ + "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", + "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'Microsoft.KubernetesConfiguration/extensions', 'dapr')]" + ] + }, + { + "condition": "[parameters('daprAddon')]", + "type": "Microsoft.KubernetesConfiguration/extensions", + "apiVersion": "2023-05-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]", + "name": "dapr", + "properties": { + "extensionType": "Microsoft.Dapr", + "autoUpgradeMinorVersion": true, + "releaseTrain": "Stable", + "configurationSettings": { + "global.ha.enabled": "[format('{0}', parameters('daprAddonHA'))]" + }, + "scope": { + "cluster": { + "releaseNamespace": "dapr-system" + } + }, + "configurationProtectedSettings": {} + }, + "dependsOn": [ + "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" + ] + } + ], + "outputs": { + "aksClusterName": { + "type": "string", + "value": "[if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))]" + }, + "aksOidcIssuerUrl": { + "type": "string", + "value": "[if(parameters('oidcIssuer'), reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').oidcIssuerProfile.issuerURL, '')]" + }, + "userNodePoolName": { + "type": "string", + "value": "[parameters('nodePoolName')]" + }, + "systemNodePoolName": { + "type": "string", + "value": "[if(parameters('JustUseSystemPool'), parameters('nodePoolName'), 'npsystem')]" + }, + "aksPrivateDnsZone": { + "type": "string", + "value": "[variables('aksPrivateDnsZone')]" + }, + "privateFQDN": { + "type": "string", + "value": "[if(and(parameters('enablePrivateCluster'), not(equals(parameters('privateClusterDnsMethod'), 'none'))), reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').privateFQDN, '')]" + }, + "aksPrivateDnsZoneName": { + "type": "string", + "value": "[if(and(parameters('enablePrivateCluster'), not(equals(parameters('privateClusterDnsMethod'), 'none'))), join(skip(split(reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').privateFQDN, '.'), 1), '.'), '')]" + }, + "aksOidcFedIdentityProperties": { + "type": "object", + "metadata": { + "description": "This output can be directly leveraged when creating a ManagedId Federated Identity" + }, + "value": { + "issuer": "[if(parameters('oidcIssuer'), reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').oidcIssuerProfile.issuerURL, '')]", + "audiences": [ + "api://AzureADTokenExchange" + ], + "subject": "system:serviceaccount:ns:svcaccount" + } + }, + "aksNodeResourceGroup": { + "type": "string", + "metadata": { + "description": "The name of the managed resource group AKS uses" + }, + "value": "[reference(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), '2023-10-01').nodeResourceGroup]" + }, + "aksResourceId": { + "type": "string", + "metadata": { + "description": "The Azure resource id for the AKS cluster" + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name')))]" + }, + "fluxReleaseNamespace": { + "type": "string", + "value": "[if(parameters('fluxGitOpsAddon'), reference(extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'Microsoft.KubernetesConfiguration/extensions', 'flux'), '2023-05-01').scope.cluster.releaseNamespace, '')]" + }, + "daprReleaseNamespace": { + "type": "string", + "value": "[if(parameters('daprAddon'), reference(extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', if(greater(length(variables('name')), 63), substring(variables('name'), 0, 63), variables('name'))), 'Microsoft.KubernetesConfiguration/extensions', 'dapr'), '2023-05-01').scope.cluster.releaseNamespace, '')]" + } + } + } } }, - { - "condition": "[not(equals(parameters('storageName'), ''))]", - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", - "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageTableContributor'))]", + "pool1": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-pool1', parameters('bladeConfig').sectionName)]", "properties": { - "roleDefinitionId": "[variables('storageTableContributor')]", - "principalType": "ServicePrincipal", - "principalId": "[parameters('identityprincipalId')]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-federated-cred-ns_dev-sample', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, copyIndex()))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-helm-appconfig-provider', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "aksName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksClusterName.value]" - }, - "location": { - "value": "[parameters('location')]" - }, - "newOrExistingManagedIdentity": { - "value": "existing" - }, - "managedIdentityName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value]" - }, - "existingManagedIdentitySubId": { - "value": "[subscription().subscriptionId]" - }, - "existingManagedIdentityResourceGroupName": { - "value": "[resourceGroup().name]" - }, - "commands": { - "value": [ - "helm install azureappconfiguration.kubernetesprovider oci://mcr.microsoft.com/azure-app-configuration/helmchart/kubernetes-provider --namespace azappconfig-system --create-namespace" - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "15573168867133922782" - }, - "name": "AKS Run Command Script", - "description": "An Azure CLI Deployment Script that allows you to run a command on a Kubernetes cluster.", - "owner": "Aks-Bicep-Accelerator-Maintainers" - }, - "parameters": { - "aksName": { - "type": "string", - "metadata": { - "description": "The name of the Azure Kubernetes Service" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location to deploy the resources to" - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "How the deployment script should be forced to execute" - } - }, - "rbacRolesNeeded": { - "type": "array", - "defaultValue": [ - "b24988ac-6180-42a0-ab88-20f7382dd24c", - "7f6c6a51-bcf8-42ba-9220-52d62157d7db" - ], - "metadata": { - "description": "An array of Azure RoleIds that are required for the DeploymentScript resource" - } - }, - "newOrExistingManagedIdentity": { - "type": "string", - "defaultValue": "new", - "allowedValues": [ - "new", - "existing" - ], - "metadata": { - "description": "Create \"new\" or use \"existing\" Managed Identity. Default: new" - } - }, - "managedIdentityName": { - "type": "string", - "defaultValue": "[format('id-AksRunCommandProxy-{0}', parameters('location'))]", - "metadata": { - "description": "Name of the Managed Identity resource" - } - }, - "existingManagedIdentitySubId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "For an existing Managed Identity, the Subscription Id it is located in" - } - }, - "existingManagedIdentityResourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "For an existing Managed Identity, the Resource Group it is located in" - } - }, - "commands": { - "type": "array", - "metadata": { - "description": "An array of commands to run" - } - }, - "initialScriptDelay": { - "type": "string", - "defaultValue": "120s", - "metadata": { - "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" - } + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "AksName": { + "value": "[reference('cluster').outputs.aksClusterName.value]" + }, + "PoolName": { + "value": "poolz1" + }, + "agentVMSize": { + "value": "[variables('elasticPoolPresets')[parameters('clusterSize')].vmSize]" + }, + "agentCount": { + "value": 2 + }, + "agentCountMax": { + "value": 4 + }, + "availabilityZones": { + "value": [ + "1" + ] + }, + "subnetId": { + "value": "[parameters('aksSubnetId')]" + }, + "podSubnetId": { + "value": "[parameters('podSubnetId')]" + }, + "nodeTaints": { + "value": [ + "app=cluster:NoSchedule" + ] + }, + "nodeLabels": { + "value": { + "app": "cluster" + } + } + }, + "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": "4785881005530943280" + } + }, + "parameters": { + "AksName": { + "type": "string" + }, + "PoolName": { + "type": "string" + }, + "availabilityZones": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The zones to use for a node pool" + } + }, + "osDiskType": { + "type": "string", + "defaultValue": "Ephemeral", + "metadata": { + "description": "OS disk type" + } + }, + "agentVMSize": { + "type": "string", + "defaultValue": "Standard_DS3_v2", + "metadata": { + "description": "VM SKU" + } + }, + "osDiskSizeGB": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Disk size in GB" + } + }, + "agentCount": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "The number of agents for the user node pool" + } + }, + "agentCountMax": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "The maximum number of nodes for the user node pool" + } + }, + "maxPods": { + "type": "int", + "defaultValue": 30, + "metadata": { + "description": "The maximum number of pods per node." + } + }, + "nodeTaints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Any taints that should be applied to the node pool" + } + }, + "nodeLabels": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Any labels that should be applied to the node pool" + } + }, + "subnetId": { + "type": "string", + "metadata": { + "description": "The subnet the node pool will use" + } + }, + "podSubnetId": { + "type": "string", + "metadata": { + "description": "The subnet the pods will use" + } + }, + "osType": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "OS Type for the node pool" + } + } + }, + "variables": { + "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]" + }, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters/agentPools", + "apiVersion": "2023-10-02-preview", + "name": "[format('{0}/{1}', parameters('AksName'), parameters('PoolName'))]", + "properties": { + "mode": "User", + "vmSize": "[parameters('agentVMSize')]", + "count": "[parameters('agentCount')]", + "minCount": "[if(variables('autoScale'), parameters('agentCount'), null())]", + "maxCount": "[if(variables('autoScale'), parameters('agentCountMax'), null())]", + "enableAutoScaling": "[variables('autoScale')]", + "availabilityZones": "[if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null())]", + "osDiskType": "[parameters('osDiskType')]", + "osDiskSizeGB": "[parameters('osDiskSizeGB')]", + "osType": "[parameters('osType')]", + "maxPods": "[parameters('maxPods')]", + "type": "VirtualMachineScaleSets", + "vnetSubnetID": "[if(not(empty(parameters('subnetId'))), parameters('subnetId'), null())]", + "podSubnetID": "[if(not(empty(parameters('podSubnetId'))), parameters('podSubnetId'), null())]", + "upgradeSettings": { + "maxSurge": "33%" + }, + "nodeTaints": "[parameters('nodeTaints')]", + "nodeLabels": "[parameters('nodeLabels')]" + } + } + ] + } + }, + "dependsOn": [ + "cluster" + ] }, - "cleanupPreference": { - "type": "string", - "defaultValue": "OnSuccess", - "allowedValues": [ - "OnSuccess", - "OnExpiration", - "Always" - ], - "metadata": { - "description": "When the script resource is cleaned up" - } + "pool2": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-pool2', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "AksName": { + "value": "[reference('cluster').outputs.aksClusterName.value]" + }, + "PoolName": { + "value": "poolz2" + }, + "agentVMSize": { + "value": "[variables('elasticPoolPresets')[parameters('clusterSize')].vmSize]" + }, + "agentCount": { + "value": 2 + }, + "agentCountMax": { + "value": 4 + }, + "availabilityZones": { + "value": [ + "2" + ] + }, + "subnetId": { + "value": "[parameters('aksSubnetId')]" + }, + "podSubnetId": { + "value": "[parameters('podSubnetId')]" + }, + "nodeTaints": { + "value": [ + "app=cluster:NoSchedule" + ] + }, + "nodeLabels": { + "value": { + "app": "cluster" + } + } + }, + "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": "4785881005530943280" + } + }, + "parameters": { + "AksName": { + "type": "string" + }, + "PoolName": { + "type": "string" + }, + "availabilityZones": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The zones to use for a node pool" + } + }, + "osDiskType": { + "type": "string", + "defaultValue": "Ephemeral", + "metadata": { + "description": "OS disk type" + } + }, + "agentVMSize": { + "type": "string", + "defaultValue": "Standard_DS3_v2", + "metadata": { + "description": "VM SKU" + } + }, + "osDiskSizeGB": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Disk size in GB" + } + }, + "agentCount": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "The number of agents for the user node pool" + } + }, + "agentCountMax": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "The maximum number of nodes for the user node pool" + } + }, + "maxPods": { + "type": "int", + "defaultValue": 30, + "metadata": { + "description": "The maximum number of pods per node." + } + }, + "nodeTaints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Any taints that should be applied to the node pool" + } + }, + "nodeLabels": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Any labels that should be applied to the node pool" + } + }, + "subnetId": { + "type": "string", + "metadata": { + "description": "The subnet the node pool will use" + } + }, + "podSubnetId": { + "type": "string", + "metadata": { + "description": "The subnet the pods will use" + } + }, + "osType": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "OS Type for the node pool" + } + } + }, + "variables": { + "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]" + }, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters/agentPools", + "apiVersion": "2023-10-02-preview", + "name": "[format('{0}/{1}', parameters('AksName'), parameters('PoolName'))]", + "properties": { + "mode": "User", + "vmSize": "[parameters('agentVMSize')]", + "count": "[parameters('agentCount')]", + "minCount": "[if(variables('autoScale'), parameters('agentCount'), null())]", + "maxCount": "[if(variables('autoScale'), parameters('agentCountMax'), null())]", + "enableAutoScaling": "[variables('autoScale')]", + "availabilityZones": "[if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null())]", + "osDiskType": "[parameters('osDiskType')]", + "osDiskSizeGB": "[parameters('osDiskSizeGB')]", + "osType": "[parameters('osType')]", + "maxPods": "[parameters('maxPods')]", + "type": "VirtualMachineScaleSets", + "vnetSubnetID": "[if(not(empty(parameters('subnetId'))), parameters('subnetId'), null())]", + "podSubnetID": "[if(not(empty(parameters('podSubnetId'))), parameters('podSubnetId'), null())]", + "upgradeSettings": { + "maxSurge": "33%" + }, + "nodeTaints": "[parameters('nodeTaints')]", + "nodeLabels": "[parameters('nodeLabels')]" + } + } + ] + } + }, + "dependsOn": [ + "cluster" + ] }, - "isCrossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Set to true when deploying template across tenants" - } - } - }, - "variables": { - "$fxv#0": "#!/bin/bash\n\nset -e +H\n# -e to exit on error\n# +H to prevent history expansion\n\nif [ \"$loopIndex\" == \"0\" ] && [ \"$initialDelay\" != \"0\" ]\nthen\n echo \"Waiting on RBAC replication ($initialDelay)\"\n sleep $initialDelay\n\n #Force RBAC refresh\n az logout\n az login --identity\nfi\n\necho \"Sending command $command to AKS Cluster $aksName in $RG\"\ncmdOut=$(az aks command invoke -g $RG -n $aksName -o json --command \"${command}\")\necho $cmdOut\n\njsonOutputString=$cmdOut\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH\n", - "useExistingManagedIdentity": "[equals(parameters('newOrExistingManagedIdentity'), 'existing')]", - "delegatedManagedIdentityResourceId": "[if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]" - }, - "resources": [ - { - "condition": "[not(variables('useExistingManagedIdentity'))]", - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[parameters('managedIdentityName')]", - "location": "[parameters('location')]" + "pool3": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-pool3', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "AksName": { + "value": "[reference('cluster').outputs.aksClusterName.value]" + }, + "PoolName": { + "value": "poolz3" + }, + "agentVMSize": { + "value": "[variables('elasticPoolPresets')[parameters('clusterSize')].vmSize]" + }, + "agentCount": { + "value": 2 + }, + "agentCountMax": { + "value": 4 + }, + "availabilityZones": { + "value": [ + "3" + ] + }, + "subnetId": { + "value": "[parameters('aksSubnetId')]" + }, + "podSubnetId": { + "value": "[parameters('podSubnetId')]" + }, + "nodeTaints": { + "value": [ + "app=cluster:NoSchedule" + ] + }, + "nodeLabels": { + "value": { + "app": "cluster" + } + } + }, + "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": "4785881005530943280" + } + }, + "parameters": { + "AksName": { + "type": "string" + }, + "PoolName": { + "type": "string" + }, + "availabilityZones": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The zones to use for a node pool" + } + }, + "osDiskType": { + "type": "string", + "defaultValue": "Ephemeral", + "metadata": { + "description": "OS disk type" + } + }, + "agentVMSize": { + "type": "string", + "defaultValue": "Standard_DS3_v2", + "metadata": { + "description": "VM SKU" + } + }, + "osDiskSizeGB": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Disk size in GB" + } + }, + "agentCount": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "The number of agents for the user node pool" + } + }, + "agentCountMax": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "The maximum number of nodes for the user node pool" + } + }, + "maxPods": { + "type": "int", + "defaultValue": 30, + "metadata": { + "description": "The maximum number of pods per node." + } + }, + "nodeTaints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Any taints that should be applied to the node pool" + } + }, + "nodeLabels": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Any labels that should be applied to the node pool" + } + }, + "subnetId": { + "type": "string", + "metadata": { + "description": "The subnet the node pool will use" + } + }, + "podSubnetId": { + "type": "string", + "metadata": { + "description": "The subnet the pods will use" + } + }, + "osType": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "OS Type for the node pool" + } + } + }, + "variables": { + "autoScale": "[greater(parameters('agentCountMax'), parameters('agentCount'))]" + }, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters/agentPools", + "apiVersion": "2023-10-02-preview", + "name": "[format('{0}/{1}', parameters('AksName'), parameters('PoolName'))]", + "properties": { + "mode": "User", + "vmSize": "[parameters('agentVMSize')]", + "count": "[parameters('agentCount')]", + "minCount": "[if(variables('autoScale'), parameters('agentCount'), null())]", + "maxCount": "[if(variables('autoScale'), parameters('agentCountMax'), null())]", + "enableAutoScaling": "[variables('autoScale')]", + "availabilityZones": "[if(not(empty(parameters('availabilityZones'))), parameters('availabilityZones'), null())]", + "osDiskType": "[parameters('osDiskType')]", + "osDiskSizeGB": "[parameters('osDiskSizeGB')]", + "osType": "[parameters('osType')]", + "maxPods": "[parameters('maxPods')]", + "type": "VirtualMachineScaleSets", + "vnetSubnetID": "[if(not(empty(parameters('subnetId'))), parameters('subnetId'), null())]", + "podSubnetID": "[if(not(empty(parameters('podSubnetId'))), parameters('podSubnetId'), null())]", + "upgradeSettings": { + "maxSurge": "33%" + }, + "nodeTaints": "[parameters('nodeTaints')]", + "nodeLabels": "[parameters('nodeLabels')]" + } + } + ] + } + }, + "dependsOn": [ + "cluster" + ] + }, + "appIdentity": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-user-managed-identity', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('id-{0}{1}', replace(parameters('bladeConfig').sectionName, '-', ''), uniqueString(resourceGroup().id, parameters('bladeConfig').sectionName))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "federatedIdentityCredentials": { + "value": [ + { + "audiences": [ + "api://AzureADTokenExchange" + ], + "issuer": "[reference('cluster').outputs.aksOidcIssuerUrl.value]", + "name": "federated-ns_default", + "subject": "system:serviceaccount:default:workload-identity-sa" + } + ] + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "17425686371279834860" + }, + "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": { + "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 User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "type": "array", + "defaultValue": [], + "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 telemetry via a Globally Unique Identifier (GUID)." + } + } + }, + "variables": { + "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 (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.managedidentity-userassignedidentity.{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" + } + } + } + } + }, + "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(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', 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": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(parameters('federatedIdentityCredentials'))]" + }, + "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": "[parameters('federatedIdentityCredentials')[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[parameters('federatedIdentityCredentials')[copyIndex()].audiences]" + }, + "issuer": { + "value": "[parameters('federatedIdentityCredentials')[copyIndex()].issuer]" + }, + "subject": { + "value": "[parameters('federatedIdentityCredentials')[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.23.1.45101", + "templateHash": "4906524580099045986" + }, + "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": [ + "cluster" + ] }, - { - "copy": { - "name": "rbac", - "count": "[length(parameters('rbacRolesNeeded'))]" + "federatedCredsDevSample": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-federated-cred-ns_dev-sample', parameters('bladeConfig').sectionName)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "federated-ns_dev-sample" + }, + "audiences": { + "value": [ + "api://AzureADTokenExchange" + ] + }, + "issuer": { + "value": "[reference('cluster').outputs.aksOidcIssuerUrl.value]" + }, + "userAssignedIdentityName": { + "value": "[reference('appIdentity').outputs.name.value]" + }, + "subject": { + "value": "system:serviceaccount:dev-sample:workload-identity-sa" + } + }, + "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": "15826270550299120709" + }, + "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]" + } + } + } }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('aksName'))]", - "name": "[guid(resourceId('Microsoft.ContainerService/managedClusters', parameters('aksName')), parameters('rbacRolesNeeded')[copyIndex()], if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]", + "dependsOn": [ + "appIdentity", + "cluster" + ] + }, + "federatedCredsConfigMaps": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-federated-cred-ns_config-maps', parameters('bladeConfig').sectionName)]", "properties": { - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeeded')[copyIndex()])]", - "principalId": "[if(variables('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId)]", - "principalType": "ServicePrincipal", - "delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "federated-ns_azappconfig-system" + }, + "audiences": { + "value": [ + "api://AzureADTokenExchange" + ] + }, + "issuer": { + "value": "[reference('cluster').outputs.aksOidcIssuerUrl.value]" + }, + "userAssignedIdentityName": { + "value": "[reference('appIdentity').outputs.name.value]" + }, + "subject": { + "value": "system:serviceaccount:azappconfig-system:az-appconfig-k8s-provider" + } + }, + "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": "15826270550299120709" + }, + "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": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" + "appIdentity", + "cluster", + "federatedCredsDevSample" ] }, - { - "copy": { - "name": "runAksCommand", - "count": "[length(parameters('commands'))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deploymentScripts", - "apiVersion": "2020-10-01", - "name": "[format('script-{0}-{1}-{2}', parameters('aksName'), deployment().name, copyIndex())]", - "location": "[parameters('location')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} - } - }, - "kind": "AzureCLI", + "appRoleAssignments": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-user-managed-identity-rbac', parameters('bladeConfig').sectionName)]", "properties": { - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "azCliVersion": "2.35.0", - "timeout": "PT10M", - "retentionInterval": "P1D", - "environmentVariables": [ - { - "name": "RG", - "value": "[resourceGroup().name]" - }, - { - "name": "aksName", - "value": "[parameters('aksName')]" - }, - { - "name": "command", - "value": "[parameters('commands')[copyIndex()]]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "identityprincipalId": { + "value": "[reference('appIdentity').outputs.principalId.value]" }, - { - "name": "initialDelay", - "value": "[parameters('initialScriptDelay')]" + "kvName": { + "value": "[parameters('kvName')]" }, - { - "name": "loopIndex", - "value": "[string(copyIndex())]" - } - ], - "scriptContent": "[variables('$fxv#0')]", - "cleanupPreference": "[parameters('cleanupPreference')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", - "rbac" - ] - } - ], - "outputs": { - "commandOutput": { - "type": "array", - "metadata": { - "description": "Array of command output from each Deployment Script AKS run command" - }, - "copy": { - "count": "[length(parameters('commands'))]", - "input": { - "Index": "[copyIndex()]", - "Name": "[format('script-{0}-{1}-{2}', parameters('aksName'), deployment().name, copyIndex())]", - "CommandOutput": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}-{2}', parameters('aksName'), deployment().name, copyIndex())), '2020-10-01').outputs]" - } - } - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('commonLayerConfig').name))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-appconfig', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "resourceName": { - "value": "[variables('serviceLayerConfig').name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": { - "layer": "[variables('serviceLayerConfig').displayName]" - } - }, - "roleAssignments": { - "value": [ - { - "roleDefinitionIdOrName": "App Configuration Data Reader", - "principalIds": [ - "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name)), '2022-09-01').outputs.principalId.value]" - ], - "principalType": "ServicePrincipal" - } - ] - }, - "keyValues": { - "value": "[concat(createArray(createObject('name', 'Settings:Message', 'value', 'Hello from App Configuration', 'contentType', 'text/plain', 'label', 'configmap-devsample'), createObject('name', 'Settings:StorageAccountName', 'value', reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, 0)), '2022-09-01').outputs.name.value, 'contentType', 'text/plain', 'label', 'configmap-devsample')))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "14285664342099441982" - }, - "name": "App Configuration", - "description": "This module deploys an App Configuration.", - "owner": "Azure/azure-global-energy" - }, - "parameters": { - "resourceName": { - "type": "string", - "minLength": 3, - "maxLength": 48, - "metadata": { - "description": "Used to name all resources" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Resource Location." - } - }, - "lock": { - "type": "string", - "defaultValue": "NotSpecified", - "allowedValues": [ - "CanNotDelete", - "NotSpecified", - "ReadOnly" - ], - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Tags." - } - }, - "sku": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Free", - "Standard" - ], - "metadata": { - "description": "Optional. Pricing tier of App Configuration." - } - }, - "createMode": { - "type": "string", - "defaultValue": "Default", - "allowedValues": [ - "Default", - "Recover" - ], - "metadata": { - "description": "Optional. Indicates whether the configuration store need to be recovered." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Disables all authentication methods other than AAD authentication." - } - }, - "systemAssignedIdentity": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedIdentities": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The ID(s) to assign to the resource." - } - }, - "keyValues": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. All Key / Values to create." - } - }, - "roleAssignments": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" - } - }, - "diagnosticWorkspaceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace." - } - }, - "diagnosticStorageAccountId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account." - } - }, - "diagnosticEventHubAuthorizationRuleId": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticEventHubName": { - "type": "string", - "defaultValue": "", - "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." - } - }, - "diagnosticLogsRetentionInDays": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 365, - "metadata": { - "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." - } - }, - "logsToEnable": { - "type": "array", - "defaultValue": [ - "HttpRequest", - "Audit" - ], - "allowedValues": [ - "HttpRequest", - "Audit" - ], - "metadata": { - "description": "Optional. The name of logs that will be streamed." - } - }, - "metricsToEnable": { - "type": "array", - "defaultValue": [ - "AllMetrics" - ], - "allowedValues": [ - "AllMetrics" - ], - "metadata": { - "description": "Optional. The name of metrics that will be streamed." - } - }, - "cmekConfiguration": { - "type": "object", - "defaultValue": { - "kvUrl": "", - "keyName": "", - "identityId": "" - }, - "metadata": { - "description": "Optional. Customer Managed Encryption Key." - } - }, - "privateLinkSettings": { - "type": "object", - "defaultValue": { - "subnetId": "1", - "vnetId": "1" - }, - "metadata": { - "description": "Settings Required to Enable Private Link" - } - } - }, - "variables": { - "copy": [ - { - "name": "diagnosticsLogs", - "count": "[length(parameters('logsToEnable'))]", - "input": { - "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" - } - } - }, - { - "name": "diagnosticsMetrics", - "count": "[length(parameters('metricsToEnable'))]", - "input": { - "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", - "timeGrain": null, - "enabled": true, - "retentionPolicy": { - "enabled": true, - "days": "[parameters('diagnosticLogsRetentionInDays')]" + "storageName": { + "value": "[parameters('storageName')]" } + }, + "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": "12432504803735547534" + } + }, + "parameters": { + "identityprincipalId": { + "type": "string" + }, + "kvName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The name of the Azure Key Vault" + } + }, + "storageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The name of the Azure Storage Account" + } + } + }, + "variables": { + "keyVaultSecretsUser": "[resourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "storageFileDataSmbShareReader": "[resourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "storageBlobContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "storageTableContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]" + }, + "resources": [ + { + "condition": "[not(equals(parameters('kvName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), variables('keyVaultSecretsUser'))]", + "properties": { + "roleDefinitionId": "[variables('keyVaultSecretsUser')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + }, + { + "condition": "[not(equals(parameters('storageName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageFileDataSmbShareReader'))]", + "properties": { + "roleDefinitionId": "[variables('storageFileDataSmbShareReader')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + }, + { + "condition": "[not(equals(parameters('storageName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageBlobContributor'))]", + "properties": { + "roleDefinitionId": "[variables('storageBlobContributor')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + }, + { + "condition": "[not(equals(parameters('storageName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageTableContributor'))]", + "properties": { + "roleDefinitionId": "[variables('storageTableContributor')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + } + ] } - } - ], - "name": "[format('ac-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", - "enableCMEK": "[if(and(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), not(empty(parameters('cmekConfiguration').identityId))), true(), false())]", - "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", - "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", - "privateEndpointName": "[format('{0}-PrivateEndpoint', variables('name'))]", - "publicDNSZoneForwarder": "azconfig.io", - "privateDnsZoneName": "[format('privatelink.{0}', variables('publicDNSZoneForwarder'))]" - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores", - "apiVersion": "2022-05-01", - "name": "[if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "identity": "[if(not(empty(parameters('userAssignedIdentities'))), createObject('type', variables('identityType'), 'userAssignedIdentities', parameters('userAssignedIdentities')), createObject('type', variables('identityType')))]", - "properties": { - "createMode": "[parameters('createMode')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryption": "[if(variables('enableCMEK'), createObject('keyVaultProperties', createObject('identityClientId', parameters('cmekConfiguration').identityId, 'keyIdentifier', format('{0}/keys/{1}', parameters('cmekConfiguration').kvUrl, parameters('cmekConfiguration').keyName))), null())]" - } - }, - { - "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2017-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]", - "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')), parameters('lock'))]", - "properties": { - "level": "[parameters('lock')]", - "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" }, "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + "appIdentity", + "federatedCredsConfigMaps" ] }, - { - "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]", - "name": "appconfig-diagnostics", - "properties": { - "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", - "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", - "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", - "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", - "metrics": "[variables('diagnosticsMetrics')]", - "logs": "[variables('diagnosticsLogs')]" + "appRoleAssignments2": { + "copy": { + "name": "appRoleAssignments2", + "count": "[length(parameters('partitionStorageNames'))]" }, - "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[variables('privateDnsZoneName')]", - "location": "global", - "properties": {} - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2022-01-01", - "name": "[variables('privateEndpointName')]", - "location": "[parameters('location')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-user-managed-identity-rbac-{1}', parameters('bladeConfig').sectionName, parameters('partitionStorageNames')[copyIndex()])]", "properties": { - "privateLinkServiceConnections": [ - { - "name": "[variables('privateEndpointName')]", - "properties": { - "privateLinkServiceId": "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]", - "groupIds": [ - "configurationStores" - ] - } + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "identityprincipalId": { + "value": "[reference('appIdentity').outputs.principalId.value]" + }, + "storageName": { + "value": "[parameters('partitionStorageNames')[copyIndex()]]" } - ], - "subnet": { - "id": "[parameters('privateLinkSettings').subnetId]" + }, + "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": "12432504803735547534" + } + }, + "parameters": { + "identityprincipalId": { + "type": "string" + }, + "kvName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The name of the Azure Key Vault" + } + }, + "storageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The name of the Azure Storage Account" + } + } + }, + "variables": { + "keyVaultSecretsUser": "[resourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "storageFileDataSmbShareReader": "[resourceId('Microsoft.Authorization/roleDefinitions', 'aba4ae5f-2193-4029-9191-0cb91df5e314')]", + "storageBlobContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", + "storageTableContributor": "[resourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]" + }, + "resources": [ + { + "condition": "[not(equals(parameters('kvName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('kvName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.KeyVault/vaults', parameters('kvName')), variables('keyVaultSecretsUser'))]", + "properties": { + "roleDefinitionId": "[variables('keyVaultSecretsUser')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + }, + { + "condition": "[not(equals(parameters('storageName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageFileDataSmbShareReader'))]", + "properties": { + "roleDefinitionId": "[variables('storageFileDataSmbShareReader')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + }, + { + "condition": "[not(equals(parameters('storageName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageBlobContributor'))]", + "properties": { + "roleDefinitionId": "[variables('storageBlobContributor')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + }, + { + "condition": "[not(equals(parameters('storageName'), ''))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', parameters('storageName'))]", + "name": "[guid(parameters('identityprincipalId'), resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), variables('storageTableContributor'))]", + "properties": { + "roleDefinitionId": "[variables('storageTableContributor')]", + "principalType": "ServicePrincipal", + "principalId": "[parameters('identityprincipalId')]" + } + } + ] } }, "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + "appIdentity", + "federatedCredsDevSample" ] }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2022-01-01", - "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", + "helmAppConfigProvider": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-helm-appconfig-provider', parameters('bladeConfig').sectionName)]", "properties": { - "privateDnsZoneConfigs": [ - { - "name": "dnsConfig", - "properties": { - "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "aksName": { + "value": "[reference('cluster').outputs.aksClusterName.value]" + }, + "location": { + "value": "[parameters('location')]" + }, + "newOrExistingManagedIdentity": { + "value": "existing" + }, + "managedIdentityName": { + "value": "[parameters('managedIdentityName')]" + }, + "existingManagedIdentitySubId": { + "value": "[subscription().subscriptionId]" + }, + "existingManagedIdentityResourceGroupName": { + "value": "[resourceGroup().name]" + }, + "commands": { + "value": [ + "helm install azureappconfiguration.kubernetesprovider oci://mcr.microsoft.com/azure-app-configuration/helmchart/kubernetes-provider --namespace azappconfig-system --create-namespace" + ] + } + }, + "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": "7942012009836685921" + }, + "name": "AKS Run Command Script", + "description": "An Azure CLI Deployment Script that allows you to run a command on a Kubernetes cluster.", + "owner": "Aks-Bicep-Accelerator-Maintainers" + }, + "parameters": { + "aksName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Kubernetes Service" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location to deploy the resources to" + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "How the deployment script should be forced to execute" + } + }, + "rbacRolesNeeded": { + "type": "array", + "defaultValue": [ + "b24988ac-6180-42a0-ab88-20f7382dd24c", + "7f6c6a51-bcf8-42ba-9220-52d62157d7db" + ], + "metadata": { + "description": "An array of Azure RoleIds that are required for the DeploymentScript resource" + } + }, + "newOrExistingManagedIdentity": { + "type": "string", + "defaultValue": "new", + "allowedValues": [ + "new", + "existing" + ], + "metadata": { + "description": "Create \"new\" or use \"existing\" Managed Identity. Default: new" + } + }, + "managedIdentityName": { + "type": "string", + "defaultValue": "[format('id-AksRunCommandProxy-{0}', parameters('location'))]", + "metadata": { + "description": "Name of the Managed Identity resource" + } + }, + "existingManagedIdentitySubId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "For an existing Managed Identity, the Subscription Id it is located in" + } + }, + "existingManagedIdentityResourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "For an existing Managed Identity, the Resource Group it is located in" + } + }, + "commands": { + "type": "array", + "metadata": { + "description": "An array of commands to run" + } + }, + "initialScriptDelay": { + "type": "string", + "defaultValue": "120s", + "metadata": { + "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "OnSuccess", + "allowedValues": [ + "OnSuccess", + "OnExpiration", + "Always" + ], + "metadata": { + "description": "When the script resource is cleaned up" + } + }, + "isCrossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Set to true when deploying template across tenants" + } + } + }, + "variables": { + "$fxv#0": "#!/bin/bash\n\nset -e +H\n# -e to exit on error\n# +H to prevent history expansion\n\nif [ \"$loopIndex\" == \"0\" ] && [ \"$initialDelay\" != \"0\" ]\nthen\n echo \"Waiting on RBAC replication ($initialDelay)\"\n sleep $initialDelay\n\n #Force RBAC refresh\n az logout\n az login --identity\nfi\n\necho \"Sending command $command to AKS Cluster $aksName in $RG\"\ncmdOut=$(az aks command invoke -g $RG -n $aksName -o json --command \"${command}\")\necho $cmdOut\n\njsonOutputString=$cmdOut\necho $jsonOutputString > $AZ_SCRIPTS_OUTPUT_PATH\n", + "useExistingManagedIdentity": "[equals(parameters('newOrExistingManagedIdentity'), 'existing')]", + "delegatedManagedIdentityResourceId": "[if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]" + }, + "resources": [ + { + "condition": "[not(variables('useExistingManagedIdentity'))]", + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('managedIdentityName')]", + "location": "[parameters('location')]" + }, + { + "copy": { + "name": "rbac", + "count": "[length(parameters('rbacRolesNeeded'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('aksName'))]", + "name": "[guid(resourceId('Microsoft.ContainerService/managedClusters', parameters('aksName')), parameters('rbacRolesNeeded')[copyIndex()], if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeeded')[copyIndex()])]", + "principalId": "[if(variables('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId)]", + "principalType": "ServicePrincipal", + "delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" + ] + }, + { + "copy": { + "name": "runAksCommand", + "count": "[length(parameters('commands'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2020-10-01", + "name": "[format('script-{0}-{1}-{2}', parameters('aksName'), deployment().name, copyIndex())]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} + } + }, + "kind": "AzureCLI", + "properties": { + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "azCliVersion": "2.35.0", + "timeout": "PT10M", + "retentionInterval": "P1D", + "environmentVariables": [ + { + "name": "RG", + "value": "[resourceGroup().name]" + }, + { + "name": "aksName", + "value": "[parameters('aksName')]" + }, + { + "name": "command", + "value": "[parameters('commands')[copyIndex()]]" + }, + { + "name": "initialDelay", + "value": "[parameters('initialScriptDelay')]" + }, + { + "name": "loopIndex", + "value": "[string(copyIndex())]" + } + ], + "scriptContent": "[variables('$fxv#0')]", + "cleanupPreference": "[parameters('cleanupPreference')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", + "rbac" + ] + } + ], + "outputs": { + "commandOutput": { + "type": "array", + "metadata": { + "description": "Array of command output from each Deployment Script AKS run command" + }, + "copy": { + "count": "[length(parameters('commands'))]", + "input": { + "Index": "[copyIndex()]", + "Name": "[format('script-{0}-{1}-{2}', parameters('aksName'), deployment().name, copyIndex())]", + "CommandOutput": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}-{2}', parameters('aksName'), deployment().name, copyIndex())), '2020-10-01').outputs]" + } + } } } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]", - "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" - ] - }, - { - "condition": "[variables('enablePrivateLink')]", - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', variables('privateDnsZoneName'), 'link_to_vnet')]", - "location": "global", - "properties": { - "registrationEnabled": false, - "virtualNetwork": { - "id": "[parameters('privateLinkSettings').vnetId]" } }, "dependsOn": [ - "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + "cluster" ] }, - { - "copy": { - "name": "configurationStore_keyValues", - "count": "[length(parameters('keyValues'))]" - }, + "app_config": { "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", - "name": "[format('{0}-keyvalues-{1}', deployment().name, copyIndex())]", + "name": "[format('{0}-appconfig', parameters('bladeConfig').sectionName)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "appConfigurationName": { - "value": "[if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))]" + "resourceName": { + "value": "[parameters('bladeConfig').sectionName]" }, - "name": { - "value": "[parameters('keyValues')[copyIndex()].name]" + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": { + "layer": "[parameters('bladeConfig').displayName]" + } }, - "value": { - "value": "[parameters('keyValues')[copyIndex()].value]" + "roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "App Configuration Data Reader", + "principalIds": [ + "[reference('appIdentity').outputs.principalId.value]" + ], + "principalType": "ServicePrincipal" + } + ] }, - "label": "[if(contains(parameters('keyValues')[copyIndex()], 'label'), createObject('value', parameters('keyValues')[copyIndex()].label), createObject('value', ''))]", - "contentType": "[if(contains(parameters('keyValues')[copyIndex()], 'contentType'), createObject('value', parameters('keyValues')[copyIndex()].contentType), createObject('value', ''))]", - "tags": "[if(contains(parameters('keyValues')[copyIndex()], 'tags'), createObject('value', parameters('keyValues')[copyIndex()].tags), createObject('value', createObject()))]" + "keyValues": { + "value": "[concat(variables('appSettings'))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -22895,798 +22498,1178 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "3690091182964384757" - } + "version": "0.25.53.49325", + "templateHash": "190777283559966254" + }, + "name": "App Configuration", + "description": "This module deploys an App Configuration.", + "owner": "Azure/azure-global-energy" }, "parameters": { - "name": { + "resourceName": { "type": "string", + "minLength": 3, + "maxLength": 48, "metadata": { - "description": "Required. Name of the key." + "description": "Used to name all resources" } }, - "value": { + "location": { "type": "string", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Required. Name of the value." + "description": "Resource Location." } }, - "label": { + "lock": { "type": "string", - "defaultValue": "", + "defaultValue": "NotSpecified", + "allowedValues": [ + "CanNotDelete", + "NotSpecified", + "ReadOnly" + ], "metadata": { - "description": "Optional. Name of the Label." + "description": "Optional. Specify the type of lock." } }, - "appConfigurationName": { - "type": "string", + "tags": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + "description": "Tags." } }, - "contentType": { + "sku": { "type": "string", - "defaultValue": "", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Standard" + ], "metadata": { - "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + "description": "Optional. Pricing tier of App Configuration." } }, - "tags": { - "type": "object", - "defaultValue": {}, + "createMode": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Recover" + ], "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "variables": { - "keyValueName": "[if(empty(parameters('label')), parameters('name'), format('{0}${1}', parameters('name'), parameters('label')))]" - }, - "resources": [ - { - "type": "Microsoft.AppConfiguration/configurationStores/keyValues", - "apiVersion": "2022-05-01", - "name": "[format('{0}/{1}', parameters('appConfigurationName'), variables('keyValueName'))]", - "properties": { - "contentType": "[parameters('contentType')]", - "tags": "[parameters('tags')]", - "value": "[parameters('value')]" + "description": "Optional. Indicates whether the configuration store need to be recovered." } - } - ], - "outputs": { - "name": { - "type": "string", + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The name of the key values." - }, - "value": "[variables('keyValueName')]" + "description": "Optional. Disables all authentication methods other than AAD authentication." + } }, - "resourceId": { - "type": "string", + "systemAssignedIdentity": { + "type": "bool", + "defaultValue": false, "metadata": { - "description": "The resource ID of the key values." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), variables('keyValueName'))]" + "description": "Optional. Enables system assigned managed identity on the resource." + } }, - "resourceGroupName": { - "type": "string", + "userAssignedIdentities": { + "type": "object", + "defaultValue": {}, "metadata": { - "description": "The resource group the batch account was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" - ] - }, - { - "copy": { - "name": "configStore_rbac", - "count": "[length(parameters('roleAssignments'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", - "principalIds": { - "value": "[parameters('roleAssignments')[copyIndex()].principalIds]" - }, - "roleDefinitionIdOrName": { - "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" - }, - "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", - "resourceId": { - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('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.24.24.22086", - "templateHash": "13612500138265831088" - } - }, - "parameters": { - "principalIds": { + "description": "Optional. The ID(s) to assign to the resource." + } + }, + "keyValues": { "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. The IDs of the principals to assign the role to." + "description": "Optional. All Key / Values to create." } }, - "roleDefinitionIdOrName": { - "type": "string", + "roleAssignments": { + "type": "array", + "defaultValue": [], "metadata": { - "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + "description": "Optional. Array of objects that describe RBAC permissions, format { roleDefinitionResourceId (string), principalId (string), principalType (enum), enabled (bool) }. Ref: https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep" } }, - "resourceId": { + "diagnosticWorkspaceId": { "type": "string", + "defaultValue": "", "metadata": { - "description": "Required. The resource ID of the resource to apply the role assignment to." + "description": "Optional. Resource ID of the diagnostic log analytics workspace." } }, - "principalType": { + "diagnosticStorageAccountId": { "type": "string", "defaultValue": "", - "allowedValues": [ - "ServicePrincipal", - "Group", - "User", - "ForeignGroup", - "Device", - "" - ], "metadata": { - "description": "Optional. The principal type of the assigned principal ID." + "description": "Optional. Resource ID of the diagnostic storage account." } }, - "description": { + "diagnosticEventHubAuthorizationRuleId": { "type": "string", "defaultValue": "", "metadata": { - "description": "Optional. The description of the role assignment." + "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." } }, - "condition": { + "diagnosticEventHubName": { "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\"." + "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." } }, - "conditionVersion": { - "type": "string", - "defaultValue": "2.0", + "diagnosticLogsRetentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + }, + "logsToEnable": { + "type": "array", + "defaultValue": [ + "HttpRequest", + "Audit" + ], + "allowedValues": [ + "HttpRequest", + "Audit" + ], + "metadata": { + "description": "Optional. The name of logs that will be streamed." + } + }, + "metricsToEnable": { + "type": "array", + "defaultValue": [ + "AllMetrics" + ], "allowedValues": [ - "2.0" + "AllMetrics" ], "metadata": { - "description": "Optional. Version of the condition." + "description": "Optional. The name of metrics that will be streamed." + } + }, + "cmekConfiguration": { + "type": "object", + "defaultValue": { + "kvUrl": "", + "keyName": "", + "identityId": "" + }, + "metadata": { + "description": "Optional. Customer Managed Encryption Key." + } + }, + "privateLinkSettings": { + "type": "object", + "defaultValue": { + "subnetId": "1", + "vnetId": "1" + }, + "metadata": { + "description": "Settings Required to Enable Private Link" + } + } + }, + "variables": { + "copy": [ + { + "name": "diagnosticsLogs", + "count": "[length(parameters('logsToEnable'))]", + "input": { + "category": "[parameters('logsToEnable')[copyIndex('diagnosticsLogs')]]", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + }, + { + "name": "diagnosticsMetrics", + "count": "[length(parameters('metricsToEnable'))]", + "input": { + "category": "[parameters('metricsToEnable')[copyIndex('diagnosticsMetrics')]]", + "timeGrain": null, + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('diagnosticLogsRetentionInDays')]" + } + } + } + ], + "name": "[format('ac-{0}{1}', replace(parameters('resourceName'), '-', ''), uniqueString(resourceGroup().id, parameters('resourceName')))]", + "enableCMEK": "[if(and(and(not(empty(parameters('cmekConfiguration').kvUrl)), not(empty(parameters('cmekConfiguration').keyName))), not(empty(parameters('cmekConfiguration').identityId))), true(), false())]", + "identityType": "[if(parameters('systemAssignedIdentity'), 'SystemAssigned', if(not(empty(parameters('userAssignedIdentities'))), 'UserAssigned', 'None'))]", + "enablePrivateLink": "[and(not(equals(parameters('privateLinkSettings').vnetId, '1')), not(equals(parameters('privateLinkSettings').subnetId, '1')))]", + "privateEndpointName": "[format('{0}-PrivateEndpoint', variables('name'))]", + "publicDNSZoneForwarder": "azconfig.io", + "privateDnsZoneName": "[format('privatelink.{0}', variables('publicDNSZoneForwarder'))]" + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores", + "apiVersion": "2022-05-01", + "name": "[if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]" + }, + "identity": "[if(not(empty(parameters('userAssignedIdentities'))), createObject('type', variables('identityType'), 'userAssignedIdentities', parameters('userAssignedIdentities')), createObject('type', variables('identityType')))]", + "properties": { + "createMode": "[parameters('createMode')]", + "disableLocalAuth": "[parameters('disableLocalAuth')]", + "encryption": "[if(variables('enableCMEK'), createObject('keyVaultProperties', createObject('identityClientId', parameters('cmekConfiguration').identityId, 'keyIdentifier', format('{0}/keys/{1}', parameters('cmekConfiguration').kvUrl, parameters('cmekConfiguration').keyName))), null())]" } }, - "delegatedManagedIdentityResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Id of the delegated managed identity resource." - } - } - }, - "variables": { - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", - "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", - "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", - "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')]", - "Managed Application Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')]", - "Managed Application Operator Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", - "Managed Applications Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", - "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')]", - "Resource Policy Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')]", - "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": [ + { + "condition": "[not(equals(parameters('lock'), 'NotSpecified'))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2017-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]", + "name": "[format('{0}-{1}-lock', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')), parameters('lock'))]", + "properties": { + "level": "[parameters('lock')]", + "notes": "[if(equals(parameters('lock'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot modify the resource or child resources.')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + ] + }, + { + "condition": "[or(or(or(not(empty(parameters('diagnosticStorageAccountId'))), not(empty(parameters('diagnosticWorkspaceId')))), not(empty(parameters('diagnosticEventHubAuthorizationRuleId')))), not(empty(parameters('diagnosticEventHubName'))))]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]", + "name": "appconfig-diagnostics", + "properties": { + "storageAccountId": "[if(not(empty(parameters('diagnosticStorageAccountId'))), parameters('diagnosticStorageAccountId'), null())]", + "workspaceId": "[if(not(empty(parameters('diagnosticWorkspaceId'))), parameters('diagnosticWorkspaceId'), null())]", + "eventHubAuthorizationRuleId": "[if(not(empty(parameters('diagnosticEventHubAuthorizationRuleId'))), parameters('diagnosticEventHubAuthorizationRuleId'), null())]", + "eventHubName": "[if(not(empty(parameters('diagnosticEventHubName'))), parameters('diagnosticEventHubName'), null())]", + "metrics": "[variables('diagnosticsMetrics')]", + "logs": "[variables('diagnosticsLogs')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "[variables('privateDnsZoneName')]", + "location": "global", + "properties": {} + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2022-01-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('location')]", + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]", + "groupIds": [ + "configurationStores" + ] + } + } + ], + "subnet": { + "id": "[parameters('privateLinkSettings').subnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2022-01-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'dnsgroupname')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "dnsConfig", + "properties": { + "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]", + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] + }, + { + "condition": "[variables('enablePrivateLink')]", + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', variables('privateDnsZoneName'), 'link_to_vnet')]", + "location": "global", + "properties": { + "registrationEnabled": false, + "virtualNetwork": { + "id": "[parameters('privateLinkSettings').vnetId]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', variables('privateDnsZoneName'))]" + ] + }, + { + "copy": { + "name": "configurationStore_keyValues", + "count": "[length(parameters('keyValues'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvalues-{1}', deployment().name, copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appConfigurationName": { + "value": "[if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))]" + }, + "name": { + "value": "[parameters('keyValues')[copyIndex()].name]" + }, + "value": { + "value": "[parameters('keyValues')[copyIndex()].value]" + }, + "label": "[if(contains(parameters('keyValues')[copyIndex()], 'label'), createObject('value', parameters('keyValues')[copyIndex()].label), createObject('value', ''))]", + "contentType": "[if(contains(parameters('keyValues')[copyIndex()], 'contentType'), createObject('value', parameters('keyValues')[copyIndex()].contentType), createObject('value', ''))]", + "tags": "[if(contains(parameters('keyValues')[copyIndex()], 'tags'), createObject('value', parameters('keyValues')[copyIndex()].tags), createObject('value', createObject()))]" + }, + "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": "7152117939574789610" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the key." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Name of the value." + } + }, + "label": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Label." + } + }, + "appConfigurationName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent app configuration store. Required if the template is used in a standalone deployment." + } + }, + "contentType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The content type of the key-values value. Providing a proper content-type can enable transformations of values when they are retrieved by applications." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Tags of the resource." + } + } + }, + "variables": { + "keyValueName": "[if(empty(parameters('label')), parameters('name'), format('{0}${1}', parameters('name'), parameters('label')))]" + }, + "resources": [ + { + "type": "Microsoft.AppConfiguration/configurationStores/keyValues", + "apiVersion": "2022-05-01", + "name": "[format('{0}/{1}', parameters('appConfigurationName'), variables('keyValueName'))]", + "properties": { + "contentType": "[parameters('contentType')]", + "tags": "[parameters('tags')]", + "value": "[parameters('value')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key values." + }, + "value": "[variables('keyValueName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key values." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores/keyValues', parameters('appConfigurationName'), variables('keyValueName'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the batch account was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + ] + }, { "copy": { - "name": "roleAssignment", - "count": "[length(parameters('principalIds'))]" + "name": "configStore_rbac", + "count": "[length(parameters('roleAssignments'))]" }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', last(split(parameters('resourceId'), '/')))]", - "name": "[guid(resourceId('Microsoft.AppConfiguration/configurationStores', last(split(parameters('resourceId'), '/'))), parameters('principalIds')[copyIndex()], parameters('roleDefinitionIdOrName'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-rbac-{1}', deployment().name, copyIndex())]", "properties": { - "description": "[parameters('description')]", - "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", - "principalId": "[parameters('principalIds')[copyIndex()]]", - "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())]" - } - } - ] - } - }, - "dependsOn": [ - "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" - ] - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the azure app configuration service." - }, - "value": "[if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))]" - }, - "id": { - "type": "string", - "metadata": { - "description": "The resourceId of the azure app configuration service." - }, - "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the azure app configuration service." - }, - "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))), '2022-05-01').endpoint]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity-rbac', variables('serviceLayerConfig').name))]", - "appRoleAssignments2", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-storage-{1}', variables('partitionLayerConfig').name, 0))]" - ] - }, - { - "condition": "[variables('enableConfigMap')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-cluster-appconfig-configmap', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "aksName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksClusterName.value]" - }, - "location": { - "value": "[parameters('location')]" - }, - "name": { - "value": "config-map-values" - }, - "namespace": { - "value": "default" - }, - "fileData": { - "value": [ - "[format(variables('configMaps').appConfigTemplate, subscription().tenantId, reference(resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name)), '2022-09-01').outputs.clientId.value, reference(resourceId('Microsoft.Resources/deployments', format('{0}-appconfig', variables('serviceLayerConfig').name)), '2022-09-01').outputs.endpoint.value, reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.uri.value, reference(resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name)), '2022-09-01').outputs.name.value)]" - ] - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.24.24.22086", - "templateHash": "4801579897722142587" - }, - "name": "AKS Config Map", - "description": "An Azure CLI Deployment Script that allows you to create a helm char on a Kubernetes cluster.", - "owner": "Daniel Scholl" - }, - "parameters": { - "aksName": { - "type": "string", - "metadata": { - "description": "The name of the Azure Kubernetes Service" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location to deploy the resources to" - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "[utcNow()]", - "metadata": { - "description": "How the deployment script should be forced to execute" - } - }, - "rbacRolesNeeded": { - "type": "array", - "defaultValue": [ - "b24988ac-6180-42a0-ab88-20f7382dd24c", - "7f6c6a51-bcf8-42ba-9220-52d62157d7db" - ], - "metadata": { - "description": "An array of Azure RoleIds that are required for the DeploymentScript resource" - } - }, - "newOrExistingManagedIdentity": { - "type": "string", - "defaultValue": "new", - "allowedValues": [ - "new", - "existing" - ], - "metadata": { - "description": "Create \"new\" or use \"existing\" Managed Identity. Default: new" - } - }, - "managedIdentityName": { - "type": "string", - "defaultValue": "[format('id-AksConfigMap-{0}', parameters('location'))]", - "metadata": { - "description": "Name of the Managed Identity resource" - } - }, - "existingManagedIdentitySubId": { - "type": "string", - "defaultValue": "[subscription().subscriptionId]", - "metadata": { - "description": "For an existing Managed Identity, the Subscription Id it is located in" - } - }, - "existingManagedIdentityResourceGroupName": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "For an existing Managed Identity, the Resource Group it is located in" - } - }, - "name": { - "type": "string", - "defaultValue": "configuration", - "metadata": { - "description": "Specify the config map name." - } - }, - "namespace": { - "type": "string", - "defaultValue": "default", - "metadata": { - "description": "Specify the namespace for the config mapl" - } - }, - "propertyData": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Specify the config map single property data. (e.g. \"player_initial_lives=3\")" - } - }, - "fileData": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Specify the config map file data. (e.g. \"game.properties: |enemy.types=aliens,monsters\nplayer.maximum-lives=5\")" - } - }, - "initialScriptDelay": { - "type": "string", - "defaultValue": "120s", - "metadata": { - "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" - } - }, - "cleanupPreference": { - "type": "string", - "defaultValue": "OnSuccess", - "allowedValues": [ - "OnSuccess", - "OnExpiration", - "Always" - ], - "metadata": { - "description": "When the script resource is cleaned up" - } - }, - "isCrossTenant": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Set to true when deploying template across tenants" - } - } - }, - "variables": { - "$fxv#0": "\nset -e +H\n# -e to exit on error\n# +H to prevent history expansion\n\n# This script is used to apply a ConfigMap to an AKS cluster using the az aks command invoke command.\n\nif [ \"$initialDelay\" != \"0\" ]\nthen\n echo \"Waiting on RBAC replication ($initialDelay)\"\n sleep $initialDelay\n\n #Force RBAC refresh\n az logout\n az login --identity\nfi\n\n# Function to convert semi-colon-separated key-value pairs in $dataPropertyLike to YAML format\nconvert_properties_to_yaml() {\n local IFS=\";\"\n for pair in $dataPropertyLike; do\n IFS='=' read -r key value <<< \"$pair\"\n echo \" $key: \\\"$value\\\"\"\n done\n echo \"\" # Add an empty line for separation\n}\n\n# Function to append file-like data in $dataFileLike to YAML format, converting \\t to spaces\nappend_files_to_yaml() {\n local IFS=\";\"\n for file in $dataFileLike; do\n local name=\"${file%%: *}\"\n local content=\"${file#*: |}\"\n # Process content to ensure correct new line handling and indentation\n content=$(echo \"$content\" | sed 's/\\\\n/\\n/g' | sed 's/^/ /') # Adjust for actual new lines and indent\n echo \" $name: |\"\n echo \"$content\"\n done\n}\n\n\necho \"Checking and updating configmap $configMap in AKS Cluster $aksName in $RG\"\n\n\n# Combining property-like and file-like data into the ConfigMap\ncombinedYaml=$(cat < $AZ_SCRIPTS_OUTPUT_PATH\n", - "useExistingManagedIdentity": "[equals(parameters('newOrExistingManagedIdentity'), 'existing')]", - "delegatedManagedIdentityResourceId": "[if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]" - }, - "resources": [ - { - "condition": "[not(variables('useExistingManagedIdentity'))]", - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2023-01-31", - "name": "[parameters('managedIdentityName')]", - "location": "[parameters('location')]" - }, - { - "copy": { - "name": "rbac", - "count": "[length(parameters('rbacRolesNeeded'))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('aksName'))]", - "name": "[guid(resourceId('Microsoft.ContainerService/managedClusters', parameters('aksName')), parameters('rbacRolesNeeded')[copyIndex()], if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]", - "properties": { - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeeded')[copyIndex()])]", - "principalId": "[if(variables('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId)]", - "principalType": "ServicePrincipal", - "delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "description": "[if(contains(parameters('roleAssignments')[copyIndex()], 'description'), createObject('value', parameters('roleAssignments')[copyIndex()].description), createObject('value', ''))]", + "principalIds": { + "value": "[parameters('roleAssignments')[copyIndex()].principalIds]" + }, + "roleDefinitionIdOrName": { + "value": "[parameters('roleAssignments')[copyIndex()].roleDefinitionIdOrName]" + }, + "principalType": "[if(contains(parameters('roleAssignments')[copyIndex()], 'principalType'), createObject('value', parameters('roleAssignments')[copyIndex()].principalType), createObject('value', ''))]", + "resourceId": { + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('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": "17986507676367706960" + } + }, + "parameters": { + "principalIds": { + "type": "array", + "metadata": { + "description": "Required. The IDs of the principals to assign the role to." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource to apply the role assignment to." + } + }, + "principalType": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "ServicePrincipal", + "Group", + "User", + "ForeignGroup", + "Device", + "" + ], + "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", + "defaultValue": "2.0", + "allowedValues": [ + "2.0" + ], + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Id of the delegated managed identity resource." + } + } + }, + "variables": { + "builtInRoleNames": { + "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", + "App Compliance Automation Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ffc6bbe0-e443-4c3b-bf54-26581bb2f78e')]", + "App Configuration Data Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')]", + "App Configuration Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]", + "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')]", + "Managed Application Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')]", + "Managed Application Operator Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')]", + "Managed Applications Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')]", + "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')]", + "Resource Policy Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')]", + "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": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(parameters('principalIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.AppConfiguration/configurationStores/{0}', last(split(parameters('resourceId'), '/')))]", + "name": "[guid(resourceId('Microsoft.AppConfiguration/configurationStores', last(split(parameters('resourceId'), '/'))), parameters('principalIds')[copyIndex()], parameters('roleDefinitionIdOrName'))]", + "properties": { + "description": "[parameters('description')]", + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), parameters('roleDefinitionIdOrName')), variables('builtInRoleNames')[parameters('roleDefinitionIdOrName')], parameters('roleDefinitionIdOrName'))]", + "principalId": "[parameters('principalIds')[copyIndex()]]", + "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())]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the azure app configuration service." + }, + "value": "[if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))]" + }, + "id": { + "type": "string", + "metadata": { + "description": "The resourceId of the azure app configuration service." + }, + "value": "[resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name')))]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The endpoint of the azure app configuration service." + }, + "value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', if(greater(length(variables('name')), 50), substring(variables('name'), 0, 50), variables('name'))), '2022-05-01').endpoint]" + } + } + } }, "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" + "appIdentity", + "appRoleAssignments", + "appRoleAssignments2" ] }, - { - "type": "Microsoft.Resources/deploymentScripts", - "apiVersion": "2020-10-01", - "name": "[format('script-{0}-{1}', parameters('aksName'), deployment().name)]", - "location": "[parameters('location')]", - "identity": { - "type": "UserAssigned", - "userAssignedIdentities": { - "[format('{0}', if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} - } - }, - "kind": "AzureCLI", + "appConfigMap": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cluster-appconfig-configmap', parameters('bladeConfig').sectionName)]", "properties": { - "forceUpdateTag": "[parameters('forceUpdateTag')]", - "azCliVersion": "2.54.0", - "timeout": "PT10M", - "retentionInterval": "P1D", - "environmentVariables": [ - { - "name": "RG", - "value": "[resourceGroup().name]" - }, - { - "name": "aksName", - "value": "[parameters('aksName')]" - }, - { - "name": "configMap", - "value": "[parameters('name')]" + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "aksName": { + "value": "[reference('cluster').outputs.aksClusterName.value]" }, - { - "name": "namespace", - "value": "[parameters('namespace')]" + "location": { + "value": "[parameters('location')]" }, - { - "name": "dataPropertyLike", - "value": "[join(parameters('propertyData'), ';')]" + "name": { + "value": "config-map-values" }, - { - "name": "dataFileLike", - "value": "[join(parameters('fileData'), ';')]" + "namespace": { + "value": "default" }, - { - "name": "initialDelay", - "value": "[parameters('initialScriptDelay')]" + "fileData": { + "value": [ + "[format(variables('configMaps').appConfigTemplate, subscription().tenantId, reference('appIdentity').outputs.clientId.value, reference('app_config').outputs.endpoint.value, parameters('kvUri'), parameters('kvName'))]" + ] } - ], - "scriptContent": "[variables('$fxv#0')]", - "cleanupPreference": "[parameters('cleanupPreference')]" - }, - "dependsOn": [ - "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", - "rbac" - ] - } - ], - "outputs": { - "commandOutput": { - "type": "object", - "metadata": { - "description": "Array of command output from each Deployment Script AKS run command" - }, - "value": { - "Name": "[format('script-{0}-{1}', parameters('aksName'), deployment().name)]", - "CommandOutput": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('aksName'), deployment().name)), '2020-10-01').outputs]" - } - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-appconfig', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-user-managed-identity', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-azure-keyvault', variables('commonLayerConfig').name))]" - ] - }, - { - "condition": "[variables('enableSoftwareLoad')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-cluster-gitops', variables('serviceLayerConfig').name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('serviceLayerConfig').gitops.name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "namespace": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.fluxReleaseNamespace.value]" - }, - "clusterName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name)), '2022-09-01').outputs.aksClusterName.value]" - }, - "scope": { - "value": "cluster" - }, - "sourceKind": { - "value": "GitRepository" - }, - "gitRepository": { - "value": { - "url": "[variables('serviceLayerConfig').gitops.url]", - "timeoutInSeconds": 180, - "syncIntervalInSeconds": 300, - "repositoryRef": { - "branch": "[variables('serviceLayerConfig').gitops.branch]" - } - } - }, - "kustomizations": { - "value": { - "components": { - "path": "[variables('serviceLayerConfig').gitops.components]", - "timeoutInSeconds": 300, - "syncIntervalInSeconds": 300, - "retryIntervalInSeconds": 300, - "prune": true - }, - "applications": { - "path": "[variables('serviceLayerConfig').gitops.applications]", - "dependsOn": [ - "components" - ], - "timeoutInSeconds": 300, - "syncIntervalInSeconds": 300, - "retryIntervalInSeconds": 300, - "prune": true - } - } - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.23.1.45101", - "templateHash": "885928168160399718" - }, - "name": "Kubernetes Configuration Flux Configurations", - "description": "This module deploys a Kubernetes Configuration Flux Configuration.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Flux Configuration." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "clusterName": { - "type": "string", - "metadata": { - "description": "Required. The name of the AKS cluster that should be configured." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "bucket": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Conditional. Parameters to reconcile to the GitRepository source kind type. Required if `sourceKind` is `Bucket`." - } - }, - "configurationProtectedSettings": { - "type": "secureObject", - "nullable": true, - "metadata": { - "description": "Optional. Key-value pairs of protected configuration settings for the configuration." - } - }, - "gitRepository": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Conditional. Parameters to reconcile to the GitRepository source kind type. Required if `sourceKind` is `GitRepository`." - } - }, - "kustomizations": { - "type": "object", - "metadata": { - "description": "Required. Array of kustomizations used to reconcile the artifact pulled by the source type on the cluster." - } - }, - "namespace": { - "type": "string", - "metadata": { - "description": "Required. The namespace to which this configuration is installed to. Maximum of 253 lower case alphanumeric characters, hyphen and period only." - } - }, - "scope": { - "type": "string", - "allowedValues": [ - "cluster", - "namespace" - ], - "metadata": { - "description": "Required. Scope at which the configuration will be installed." - } - }, - "sourceKind": { - "type": "string", - "allowedValues": [ - "Bucket", - "GitRepository" - ], - "metadata": { - "description": "Required. Source Kind to pull the configuration data from." - } + }, + "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": "17662393944340422767" + }, + "name": "AKS Config Map", + "description": "An Azure CLI Deployment Script that allows you to create a helm char on a Kubernetes cluster.", + "owner": "Daniel Scholl" + }, + "parameters": { + "aksName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Kubernetes Service" + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location to deploy the resources to" + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "How the deployment script should be forced to execute" + } + }, + "rbacRolesNeeded": { + "type": "array", + "defaultValue": [ + "b24988ac-6180-42a0-ab88-20f7382dd24c", + "7f6c6a51-bcf8-42ba-9220-52d62157d7db" + ], + "metadata": { + "description": "An array of Azure RoleIds that are required for the DeploymentScript resource" + } + }, + "newOrExistingManagedIdentity": { + "type": "string", + "defaultValue": "new", + "allowedValues": [ + "new", + "existing" + ], + "metadata": { + "description": "Create \"new\" or use \"existing\" Managed Identity. Default: new" + } + }, + "managedIdentityName": { + "type": "string", + "defaultValue": "[format('id-AksConfigMap-{0}', parameters('location'))]", + "metadata": { + "description": "Name of the Managed Identity resource" + } + }, + "existingManagedIdentitySubId": { + "type": "string", + "defaultValue": "[subscription().subscriptionId]", + "metadata": { + "description": "For an existing Managed Identity, the Subscription Id it is located in" + } + }, + "existingManagedIdentityResourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "For an existing Managed Identity, the Resource Group it is located in" + } + }, + "name": { + "type": "string", + "defaultValue": "configuration", + "metadata": { + "description": "Specify the config map name." + } + }, + "namespace": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Specify the namespace for the config mapl" + } + }, + "propertyData": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Specify the config map single property data. (e.g. \"player_initial_lives=3\")" + } + }, + "fileData": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Specify the config map file data. (e.g. \"game.properties: |enemy.types=aliens,monsters\nplayer.maximum-lives=5\")" + } + }, + "initialScriptDelay": { + "type": "string", + "defaultValue": "120s", + "metadata": { + "description": "A delay before the script import operation starts. Primarily to allow Azure AAD Role Assignments to propagate" + } + }, + "cleanupPreference": { + "type": "string", + "defaultValue": "OnSuccess", + "allowedValues": [ + "OnSuccess", + "OnExpiration", + "Always" + ], + "metadata": { + "description": "When the script resource is cleaned up" + } + }, + "isCrossTenant": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Set to true when deploying template across tenants" + } + } + }, + "variables": { + "$fxv#0": "\nset -e +H\n# -e to exit on error\n# +H to prevent history expansion\n\n# This script is used to apply a ConfigMap to an AKS cluster using the az aks command invoke command.\n\nif [ \"$initialDelay\" != \"0\" ]\nthen\n echo \"Waiting on RBAC replication ($initialDelay)\"\n sleep $initialDelay\n\n #Force RBAC refresh\n az logout\n az login --identity\nfi\n\n# Function to convert semi-colon-separated key-value pairs in $dataPropertyLike to YAML format\nconvert_properties_to_yaml() {\n local IFS=\";\"\n for pair in $dataPropertyLike; do\n IFS='=' read -r key value <<< \"$pair\"\n echo \" $key: \\\"$value\\\"\"\n done\n echo \"\" # Add an empty line for separation\n}\n\n# Function to append file-like data in $dataFileLike to YAML format, converting \\t to spaces\nappend_files_to_yaml() {\n local IFS=\";\"\n for file in $dataFileLike; do\n local name=\"${file%%: *}\"\n local content=\"${file#*: |}\"\n # Process content to ensure correct new line handling and indentation\n content=$(echo \"$content\" | sed 's/\\\\n/\\n/g' | sed 's/^/ /') # Adjust for actual new lines and indent\n echo \" $name: |\"\n echo \"$content\"\n done\n}\n\n\necho \"Checking and updating configmap $configMap in AKS Cluster $aksName in $RG\"\n\n\n# Combining property-like and file-like data into the ConfigMap\ncombinedYaml=$(cat < $AZ_SCRIPTS_OUTPUT_PATH\n", + "useExistingManagedIdentity": "[equals(parameters('newOrExistingManagedIdentity'), 'existing')]", + "delegatedManagedIdentityResourceId": "[if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')))]" + }, + "resources": [ + { + "condition": "[not(variables('useExistingManagedIdentity'))]", + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('managedIdentityName')]", + "location": "[parameters('location')]" + }, + { + "copy": { + "name": "rbac", + "count": "[length(parameters('rbacRolesNeeded'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('aksName'))]", + "name": "[guid(resourceId('Microsoft.ContainerService/managedClusters', parameters('aksName')), parameters('rbacRolesNeeded')[copyIndex()], if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('rbacRolesNeeded')[copyIndex()])]", + "principalId": "[if(variables('useExistingManagedIdentity'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId, reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), '2023-01-31').principalId)]", + "principalType": "ServicePrincipal", + "delegatedManagedIdentityResourceId": "[if(parameters('isCrossTenant'), variables('delegatedManagedIdentityResourceId'), null())]" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2020-10-01", + "name": "[format('script-{0}-{1}', parameters('aksName'), deployment().name)]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', if(variables('useExistingManagedIdentity'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('existingManagedIdentitySubId'), parameters('existingManagedIdentityResourceGroupName')), 'Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))))]": {} + } + }, + "kind": "AzureCLI", + "properties": { + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "azCliVersion": "2.54.0", + "timeout": "PT10M", + "retentionInterval": "P1D", + "environmentVariables": [ + { + "name": "RG", + "value": "[resourceGroup().name]" + }, + { + "name": "aksName", + "value": "[parameters('aksName')]" + }, + { + "name": "configMap", + "value": "[parameters('name')]" + }, + { + "name": "namespace", + "value": "[parameters('namespace')]" + }, + { + "name": "dataPropertyLike", + "value": "[join(parameters('propertyData'), ';')]" + }, + { + "name": "dataFileLike", + "value": "[join(parameters('fileData'), ';')]" + }, + { + "name": "initialDelay", + "value": "[parameters('initialScriptDelay')]" + } + ], + "scriptContent": "[variables('$fxv#0')]", + "cleanupPreference": "[parameters('cleanupPreference')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]", + "rbac" + ] + } + ], + "outputs": { + "commandOutput": { + "type": "object", + "metadata": { + "description": "Array of command output from each Deployment Script AKS run command" + }, + "value": { + "Name": "[format('script-{0}-{1}', parameters('aksName'), deployment().name)]", + "CommandOutput": "[reference(resourceId('Microsoft.Resources/deploymentScripts', format('script-{0}-{1}', parameters('aksName'), deployment().name)), '2020-10-01').outputs]" + } + } + } + } + }, + "dependsOn": [ + "app_config", + "appIdentity", + "cluster" + ] }, - "suspend": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether this configuration should suspend its reconciliation of its kustomizations and sources." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", + "fluxConfiguration": { + "condition": "[parameters('enableSoftwareLoad')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2023-07-01", - "name": "[format('46d3xbcp.res.kubernetesconfiguration-fluxconfig.{0}.{1}', replace('0.3.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "apiVersion": "2022-09-01", + "name": "[format('{0}-cluster-gitops', parameters('bladeConfig').sectionName)]", "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('serviceLayerConfig').gitops.name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "namespace": { + "value": "[reference('cluster').outputs.fluxReleaseNamespace.value]" + }, + "clusterName": { + "value": "[reference('cluster').outputs.aksClusterName.value]" + }, + "scope": { + "value": "cluster" + }, + "sourceKind": { + "value": "GitRepository" + }, + "gitRepository": { + "value": { + "url": "[variables('serviceLayerConfig').gitops.url]", + "timeoutInSeconds": 180, + "syncIntervalInSeconds": 300, + "repositoryRef": { + "branch": "[variables('serviceLayerConfig').gitops.branch]" + } + } + }, + "kustomizations": { + "value": { + "components": { + "path": "[variables('serviceLayerConfig').gitops.components]", + "timeoutInSeconds": 300, + "syncIntervalInSeconds": 300, + "retryIntervalInSeconds": 300, + "prune": true + }, + "applications": { + "path": "[variables('serviceLayerConfig').gitops.applications]", + "dependsOn": [ + "components" + ], + "timeoutInSeconds": 300, + "syncIntervalInSeconds": 300, + "retryIntervalInSeconds": 300, + "prune": true + } + } + } + }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", - "resources": [], + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "885928168160399718" + }, + "name": "Kubernetes Configuration Flux Configurations", + "description": "This module deploys a Kubernetes Configuration Flux Configuration.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Flux Configuration." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Required. The name of the AKS cluster that should be configured." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "bucket": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Conditional. Parameters to reconcile to the GitRepository source kind type. Required if `sourceKind` is `Bucket`." + } + }, + "configurationProtectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Key-value pairs of protected configuration settings for the configuration." + } + }, + "gitRepository": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Conditional. Parameters to reconcile to the GitRepository source kind type. Required if `sourceKind` is `GitRepository`." + } + }, + "kustomizations": { + "type": "object", + "metadata": { + "description": "Required. Array of kustomizations used to reconcile the artifact pulled by the source type on the cluster." + } + }, + "namespace": { + "type": "string", + "metadata": { + "description": "Required. The namespace to which this configuration is installed to. Maximum of 253 lower case alphanumeric characters, hyphen and period only." + } + }, + "scope": { + "type": "string", + "allowedValues": [ + "cluster", + "namespace" + ], + "metadata": { + "description": "Required. Scope at which the configuration will be installed." + } + }, + "sourceKind": { + "type": "string", + "allowedValues": [ + "Bucket", + "GitRepository" + ], + "metadata": { + "description": "Required. Source Kind to pull the configuration data from." + } + }, + "suspend": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether this configuration should suspend its reconciliation of its kustomizations and sources." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.kubernetesconfiguration-fluxconfig.{0}.{1}', replace('0.3.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" + } + } + } + } + }, + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2022-07-01", + "name": "[parameters('clusterName')]" + }, + "fluxConfiguration": { + "type": "Microsoft.KubernetesConfiguration/fluxConfigurations", + "apiVersion": "2023-05-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('clusterName'))]", + "name": "[parameters('name')]", + "properties": { + "bucket": "[parameters('bucket')]", + "configurationProtectedSettings": "[parameters('configurationProtectedSettings')]", + "gitRepository": "[parameters('gitRepository')]", + "kustomizations": "[parameters('kustomizations')]", + "namespace": "[parameters('namespace')]", + "scope": "[parameters('scope')]", + "sourceKind": "[parameters('sourceKind')]", + "suspend": "[parameters('suspend')]" + }, + "dependsOn": [ + "managedCluster" + ] + } + }, "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + "name": { + "type": "string", + "metadata": { + "description": "The name of the flux configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the flux configuration." + }, + "value": "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName')), 'Microsoft.KubernetesConfiguration/fluxConfigurations', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the flux configuration was deployed into." + }, + "value": "[resourceGroup().name]" } } } - } - }, - "managedCluster": { - "existing": true, - "type": "Microsoft.ContainerService/managedClusters", - "apiVersion": "2022-07-01", - "name": "[parameters('clusterName')]" - }, - "fluxConfiguration": { - "type": "Microsoft.KubernetesConfiguration/fluxConfigurations", - "apiVersion": "2023-05-01", - "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('clusterName'))]", - "name": "[parameters('name')]", - "properties": { - "bucket": "[parameters('bucket')]", - "configurationProtectedSettings": "[parameters('configurationProtectedSettings')]", - "gitRepository": "[parameters('gitRepository')]", - "kustomizations": "[parameters('kustomizations')]", - "namespace": "[parameters('namespace')]", - "scope": "[parameters('scope')]", - "sourceKind": "[parameters('sourceKind')]", - "suspend": "[parameters('suspend')]" }, "dependsOn": [ - "managedCluster" + "app_config", + "appConfigMap", + "cluster", + "pool1", + "pool2", + "pool3" ] } }, "outputs": { - "name": { + "ENV_CONFIG_ENDPOINT": { "type": "string", "metadata": { - "description": "The name of the flux configuration." + "description": "The name of the azure keyvault." }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the flux configuration." - }, - "value": "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName')), 'Microsoft.KubernetesConfiguration/fluxConfigurations', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the flux configuration was deployed into." - }, - "value": "[resourceGroup().name]" + "value": "[reference('app_config').outputs.endpoint.value]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('{0}-appconfig', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-cluster-appconfig-configmap', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-aks-cluster', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-pool1', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-pool2', variables('serviceLayerConfig').name))]", - "[resourceId('Microsoft.Resources/deployments', format('{0}-pool3', variables('serviceLayerConfig').name))]" + "commonBlade", + "logAnalytics", + "networkBlade", + "partitionBlade", + "stampIdentity" ] } - ], - "outputs": { - "ENV_CONFIG_ENDPOINT": { - "type": "string", - "metadata": { - "description": "The name of the azure keyvault." - }, - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-appconfig', variables('serviceLayerConfig').name)), '2022-09-01').outputs.endpoint.value]" - } } } \ No newline at end of file diff --git a/bicep/main.bicep b/bicep/main.bicep index 70529eaf..7746e09e 100644 --- a/bicep/main.bicep +++ b/bicep/main.bicep @@ -1,5 +1,6 @@ targetScope = 'resourceGroup' + @description('Specify the Azure region to place the application definition.') param location string = resourceGroup().location @@ -9,30 +10,14 @@ param applicationClientId string @description('Feature Flag to Enable Telemetry') param enableTelemetry bool = false -///////////////// -// Security Blade -///////////////// -@description('Feature Flag to Enable Private Link') -param enablePrivateLink bool = false - -@description('Optional. Customer Managed Encryption Key.') -param cmekConfiguration object = { - kvUrl: '' - keyName: '' - identityId: '' -} - - -//*****************************************************************// -// Common Section // -//*****************************************************************// ///////////////////////////////// // Configuration ///////////////////////////////// -var commonLayerConfig = { - name: 'common' - displayName: 'Common Resources' + +var configuration = { + name: 'main' + displayName: 'Main Resources' secrets: { tenantId: 'tenant-id' subscriptionId: 'subscription-id' @@ -54,1847 +39,414 @@ var commonLayerConfig = { sku: 'PerGB2018' retention: 30 } - storage: { - sku: 'Standard_LRS' - tables: [ - 'partitionInfo' - ] - shares: [ - 'crs' - 'crs-conversion' - 'unit' - 'sample-share' - ] - } - database: { - name: 'graph-db' - throughput: 2000 - backup: 'Continuous' - graphs: [ - { - name: 'Entitlements' - automaticIndexing: true - partitionKeyPaths: [ - '/dataPartitionId' - ] - } - ] - } } - -/* - __ _______ _______ .__ __. .___________. __ .___________.____ ____ -| | | \ | ____|| \ | | | || | | |\ \ / / -| | | .--. || |__ | \| | `---| |----`| | `---| |----` \ \/ / -| | | | | || __| | . ` | | | | | | | \_ _/ -| | | '--' || |____ | |\ | | | | | | | | | -|__| |_______/ |_______||__| \__| |__| |__| |__| |__| -*/ +//*****************************************************************// +// Identity Resources // +//*****************************************************************// module stampIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.1.0' = { - name: '${commonLayerConfig.name}-user-managed-identity' + name: '${configuration.name}-user-managed-identity' params: { // Required parameters - name: 'id-${replace(commonLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, commonLayerConfig.name)}' + name: 'id-${replace(configuration.name, '-', '')}${uniqueString(resourceGroup().id, configuration.name)}' location: location enableTelemetry: enableTelemetry // Assign Tags tags: { - layer: commonLayerConfig.displayName + layer: configuration.displayName } } } - -/* -.___ ___. ______ .__ __. __ .___________. ______ .______ __ .__ __. _______ -| \/ | / __ \ | \ | | | | | | / __ \ | _ \ | | | \ | | / _____| -| \ / | | | | | | \| | | | `---| |----`| | | | | |_) | | | | \| | | | __ -| |\/| | | | | | | . ` | | | | | | | | | | / | | | . ` | | | |_ | -| | | | | `--' | | |\ | | | | | | `--' | | |\ \----.| | | |\ | | |__| | -|__| |__| \______/ |__| \__| |__| |__| \______/ | _| `._____||__| |__| \__| \______| -*/ +//*****************************************************************// +// Monitoring Resources // +//*****************************************************************// module logAnalytics 'br/public:avm/res/operational-insights/workspace:0.2.1' = { - name: '${commonLayerConfig.name}-log-analytics' + name: '${configuration.name}-log-analytics' params: { - name: 'log-${replace(commonLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, commonLayerConfig.name)}' + name: 'log-${replace(configuration.name, '-', '')}${uniqueString(resourceGroup().id, configuration.name)}' location: location enableTelemetry: enableTelemetry // Assign Tags tags: { - layer: commonLayerConfig.displayName + layer: configuration.displayName } - skuName: commonLayerConfig.logs.sku + skuName: configuration.logs.sku } - dependsOn: [ - stampIdentity - ] } +//*****************************************************************// +// Network Blade // +//*****************************************************************// -/* -.__ __. _______ .___________.____ __ ____ ______ .______ __ ___ -| \ | | | ____|| |\ \ / \ / / / __ \ | _ \ | |/ / -| \| | | |__ `---| |----` \ \/ \/ / | | | | | |_) | | ' / -| . ` | | __| | | \ / | | | | | / | < -| |\ | | |____ | | \ /\ / | `--' | | |\ \----.| . \ -|__| \__| |_______| |__| \__/ \__/ \______/ | _| `._____||__|\__\ -*/ - -///////////////// -// Network Blade -///////////////// -@description('Feature Flag to Enable VPN Gateway Functionality') -param enableVirtualWAN bool = false - -@description('VNet address prefix') -param virtualNetworkAddressPrefix string = '10.1.0.0/16' - -@description('New or Existing subnet Name') -param aksSubnetName string = 'ClusterSubnet' - -@description('Subnet address prefix') -param aksSubnetAddressPrefix string = '10.1.0.0/20' - -// - - -@description('Feature Flag to Enable VPN Gateway Functionality') -param enableVpnGateway bool = false - -@description('Shared Key for VPN Gateway') -@secure() -param vpnSharedKey string = '' - -@description('IP Address of the Remote VPN Gateway') -param remoteVpnAddress string = '' - -@description('IP Address Segment of the Remote Network') -param remoteNetworkPrefix string = '192.168.1.0/24' - -@description('New or Existing subnet Name') -param gatewaySubnetName string = 'GatewaySubnet' - -@description('Specifies the Bastion subnet IP prefix. This prefix must be within vnet IP prefix address space.') -param gatewaySubnetAddressPrefix string = '10.1.17.0/24' - -// -- +type bladeSettings = { + @description('The name of the section name') + sectionName: string + @description('The display name of the section') + displayName: string +} + +type subnetSettings = { + @description('The name of the subnet') + name: string + @description('The address range to use for the subnet') + prefix: string +} + +type vnetSettings = { + @description('The name of the resource group that contains the Virtual Network') + group: string + @description('The name of the Virtual Network') + name: string + @description('The address range to use for the Virtual Network') + prefix: string + @description('The Managed Identity ') + identityId: string + @description('The cluster subnet') + aksSubnet: subnetSettings + @description('The pod subnet') + podSubnet: subnetSettings + @description('The machine subnet') + vmSubnet: subnetSettings + @description('The bastion subnet') + bastionSubnet: subnetSettings +} @description('Feature Flag to Enable Bastion') param enableBastion bool = false -@description('New or Existing subnet Name') -param bastionSubnetName string = 'AzureBastionSubnet' - -@description('Specifies the Bastion subnet IP prefix. This prefix must be within vnet IP prefix address space.') -param bastionSubnetAddressPrefix string = '10.1.16.0/24' - -@description('Specifies the name of the subnet which contains the virtual machine.') -param vmSubnetName string = 'VmSubnet' - -@description('Specifies the address prefix of the subnet which contains the virtual machine.') -param vmSubnetAddressPrefix string = '10.1.18.0/24' - -// -- - @description('Feature Flag to Enable a Pod Subnet') param enablePodSubnet bool = false -@description('New or Existing subnet Name') -param podSubnetName string = 'PodSubnet' - -@description('Subnet address prefix') -param podSubnetAddressPrefix string = '10.1.20.0/22' - -// -- - -@description('Boolean indicating whether the VNet is new or existing') -param virtualNetworkNewOrExisting string = 'new' - -@description('Name of the Virtual Network (Optional: If exiting Network is selected)') -param virtualNetworkName string = 'osdu-network' - -@description('Resource group of the VNet (Optional: If exiting Network is selected)') -param virtualNetworkResourceGroup string = 'osdu-network' - -@minLength(9) -@maxLength(18) -@description('The address range to use for services') -param serviceCidr string = '172.16.0.0/16' - -@minLength(9) -@maxLength(18) -@description('The address range to use for the docker bridge') -param dockerBridgeCidr string = '172.17.0.1/16' - -@minLength(7) -@maxLength(15) -@description('The IP address to reserve for DNS') -param dnsServiceIP string = '172.16.0.10' - -var nsgRules = { - ssh_outbound: { - name: 'AllowSshOutbound' - properties: { - priority: 110 - protocol: '*' - access: 'Allow' - direction: 'Outbound' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: 'VirtualNetwork' - destinationPortRanges: [ - '22' - '3389' - ] - } - } - - cloud_outbound: { - name: 'AllowAzureCloudOutbound' - properties: { - priority: 120 - protocol: 'Tcp' - access: 'Allow' - direction: 'Outbound' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: 'AzureCloud' - destinationPortRange: '443' - } - } - - bastion_communication: { - name: 'AllowBastionCommunication' - properties: { - priority: 130 - protocol: '*' - access: 'Allow' - direction: 'Outbound' - sourceAddressPrefix: 'VirtualNetwork' - sourcePortRange: '*' - destinationAddressPrefix: 'VirtualNetwork' - destinationPortRanges: [ - '8080' - '5701' - ] - } - } - - allow_http_outbound: { - name: 'AllowHttpOutbound' - properties: { - priority: 140 - protocol: '*' - access: 'Allow' - direction: 'Outbound' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: 'Internet' - destinationPortRange: '80' - } - } - - gateway_manager_inbound: { - name: 'AllowGatewayManagerInbound' - properties: { - priority: 150 - protocol: 'Tcp' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: 'GatewayManager' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '443' - } - } - - load_balancer_inbound: { - name: 'AllowAzureLoadBalancerInbound' - properties: { - priority: 160 - protocol: 'Tcp' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: 'AzureLoadBalancer' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '443' - } - } - - bastion_host_communication: { - name: 'AllowBastionHostCommunication' - properties: { - priority: 170 - protocol: '*' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: 'VirtualNetwork' - sourcePortRange: '*' - destinationAddressPrefix: 'VirtualNetwork' - destinationPortRanges: [ - '8080' - '5701' - ] - } - } - - http_inbound_rule: { - name: 'AllowHttpInbound' - properties: { - priority: 200 - protocol: 'Tcp' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: 'Internet' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '80' - } - } - - https_inbound_rule: { - name: 'AllowHttpsInbound' - properties: { - priority: 210 - protocol: 'Tcp' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: 'Internet' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '443' - } - } - - ssh_inbound: { - name: 'AllowSshInbound' - properties: { - priority: 220 - protocol: 'Tcp' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: 'VirtualNetwork' - sourcePortRange: '*' - destinationAddressPrefix: 'VirtualNetwork' - destinationPortRanges: [ - '22' - '3389' - ] - } - } -} +@description('Feature Flag to Enable a Pod Subnet') +param enableVnetInjection bool = false -var subnets = { - cluster: { - name: aksSubnetName - addressPrefix: aksSubnetAddressPrefix - serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - { - service: 'Microsoft.KeyVault' - } - { - service: 'Microsoft.ContainerRegistry' - } - ] - networkSecurityGroupResourceId: virtualNetworkNewOrExisting == 'new' ? clusterNetworkSecurityGroup.outputs.resourceId :null - roleAssignments: [ - { - roleDefinitionIdOrName: 'Network Contributor' - principalId: stampIdentity.outputs.principalId - principalType: 'ServicePrincipal' - } - ] - } - pods: { - name: podSubnetName - addressPrefix: podSubnetAddressPrefix - networkSecurityGroupResourceId: virtualNetworkNewOrExisting == 'new' ? clusterNetworkSecurityGroup.outputs.resourceId :null - roleAssignments: [ - { - roleDefinitionIdOrName: 'Network Contributor' - principalId: stampIdentity.outputs.principalId - principalType: 'ServicePrincipal' - } - ] +@description('Optional. Bring your own Virtual Network.') +param vnetConfiguration vnetSettings = { + group: '' + name: '' + prefix: '' + identityId: '' + aksSubnet: { + name: '' + prefix: '' } - bastion: { - name: bastionSubnetName - addressPrefix: bastionSubnetAddressPrefix - networkSecurityGroupResourceId: enableBastion ? bastionNetworkSecurityGroup.outputs.resourceId: null + podSubnet: { + name: '' + prefix: '' } - gateway: { - name: gatewaySubnetName - addressPrefix: gatewaySubnetAddressPrefix + vmSubnet: { + name: '' + prefix: '' } - machine: { - name: vmSubnetName - addressPrefix: vmSubnetAddressPrefix - serviceEndpoints: [ - { - service: 'Microsoft.Storage' - } - { - service: 'Microsoft.KeyVault' - } - { - service: 'Microsoft.ContainerRegistry' - } - ] - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Enabled' - networkSecurityGroupResourceId: enableBastion ? machineNetworkSecurityGroup.outputs.resourceId : null + bastionSubnet: { + name: '' + prefix: '' } } -module clusterNetworkSecurityGroup 'br/public:avm/res/network/network-security-group:0.1.0' = if (virtualNetworkNewOrExisting == 'new') { - name: '${commonLayerConfig.name}-network-security-group-cluster' +module networkBlade 'modules/blade_network.bicep' = { + name: 'network-blade' params: { - name: 'nsg-common${uniqueString(resourceGroup().id, 'common')}-aks' - location: location - enableTelemetry: enableTelemetry - - // Assign Tags - tags: { - layer: commonLayerConfig.displayName + bladeConfig: { + sectionName: 'networkblade' + displayName: 'Network Resources' } - securityRules: union( - array(nsgRules.http_inbound_rule), - array(nsgRules.https_inbound_rule), - array(nsgRules.ssh_outbound) - ) - } -} - -module bastionNetworkSecurityGroup 'br/public:avm/res/network/network-security-group:0.1.0' = if (virtualNetworkNewOrExisting == 'new' && enableBastion) { - name: '${commonLayerConfig.name}-network-security-group-bastion' - params: { - name: 'nsg-common${uniqueString(resourceGroup().id, 'common')}-bastion' location: location enableTelemetry: enableTelemetry - // Assign Tags - tags: { - layer: commonLayerConfig.displayName - } + workspaceResourceId: logAnalytics.outputs.resourceId + identityId: stampIdentity.outputs.principalId - securityRules: union( - array(nsgRules.https_inbound_rule), - array(nsgRules.gateway_manager_inbound), - array(nsgRules.load_balancer_inbound), - array(nsgRules.bastion_host_communication), - array(nsgRules.ssh_outbound), - array(nsgRules.cloud_outbound), - array(nsgRules.bastion_communication), - array(nsgRules.allow_http_outbound) - ) + enableBastion: enableBastion + enablePodSubnet: enablePodSubnet + enableVnetInjection: enableVnetInjection + + vnetConfiguration: vnetConfiguration } + dependsOn: [ + stampIdentity + logAnalytics + ] } -module machineNetworkSecurityGroup 'br/public:avm/res/network/network-security-group:0.1.0' = if (virtualNetworkNewOrExisting == 'new' && enableBastion) { - name: '${commonLayerConfig.name}-network-security-group-manage' - params: { - name: 'nsg-common${uniqueString(resourceGroup().id, 'common')}-vm' - location: location - enableTelemetry: enableTelemetry - // Assign Tags - tags: { - layer: commonLayerConfig.displayName - } +//*****************************************************************// +// Common Blade // +//*****************************************************************// - securityRules: [] - } +@description('Optional. Indicates whether public access is enabled for all blobs or containers in the storage account.') +param enableBlobPublicAccess bool = false + +@description('Feature Flag to Enable Private Link') +param enablePrivateLink bool = false + +@description('Optional. Customer Managed Encryption Key.') +param cmekConfiguration object = { + kvUrl: '' + keyName: '' + identityId: '' } -module network 'br/public:avm/res/network/virtual-network:0.1.0' = if (virtualNetworkNewOrExisting == 'new') { - name: '${commonLayerConfig.name}-virtual-network' +module commonBlade 'modules/blade_common.bicep' = { + name: 'common-blade' params: { - name: 'vnet-common${uniqueString(resourceGroup().id, 'common')}' + bladeConfig: { + sectionName: 'commonblade' + displayName: 'Common Resources' + } + location: location enableTelemetry: enableTelemetry + deploymentScriptIdentity: stampIdentity.outputs.name - // Assign Tags - tags: { - layer: commonLayerConfig.displayName - } + workspaceResourceId: logAnalytics.outputs.resourceId + workspaceName: logAnalytics.outputs.name - addressPrefixes: [ - virtualNetworkAddressPrefix - ] + subnetId: networkBlade.outputs.aksSubnetId + cmekConfiguration: cmekConfiguration - // Hook up Diagnostics - diagnosticSettings: [ + enablePrivateLink: enablePrivateLink + enableBlobPublicAccess: enableBlobPublicAccess + + workspaceIdName: configuration.secrets.logAnalyticsId + workspaceKeySecretName: configuration.secrets.logAnalyticsKey + + vaultSecrets: [ { - name: 'LogAnalytics' - workspaceResourceId: logAnalytics.outputs.resourceId - metricCategories: [ - { - category: 'AllMetrics' - } - ] + secretName: configuration.secrets.tenantId + secretValue: subscription().tenantId } - ] - - // Assign RBAC - roleAssignments: [ { - roleDefinitionIdOrName: 'Reader' - principalId: stampIdentity.outputs.principalId - principalType: 'ServicePrincipal' + secretName: configuration.secrets.subscriptionId + secretValue: subscription().subscriptionId + } + // Azure AD Secrets + { + secretName: configuration.secrets.clientId + secretValue: applicationClientId + } + { + secretName: configuration.secrets.applicationPrincipalId + secretValue: applicationClientId } ] - - // Setup Subnets - subnets: union( - array(subnets.cluster), - enableBastion ? array(subnets.bastion) : [], - enableBastion ? array(subnets.machine) : [], - enableVpnGateway ? array(subnets.gateway) : [], - enablePodSubnet ? array(subnets.pods) : [] - ) } dependsOn: [ - logAnalytics - clusterNetworkSecurityGroup - bastionNetworkSecurityGroup - machineNetworkSecurityGroup + networkBlade ] } -resource virtualWan 'Microsoft.Network/virtualWans@2023-06-01' = if (enableVirtualWAN || enableVpnGateway) { - name: 'wan-common${uniqueString(resourceGroup().id, 'common')}' - location: location -} -resource virtualHub 'Microsoft.Network/virtualHubs@2023-06-01' = if (enableVirtualWAN || enableVpnGateway) { - name: 'hub-common${uniqueString(resourceGroup().id, 'common')}' - location: location - properties: { - virtualWan: { - id: virtualWan.id - } - addressPrefix: virtualNetworkAddressPrefix - } -} +//*****************************************************************// +// Manage Blade // +//*****************************************************************// -///////////////////////////////// -// VPN Gateway -module vpnSite 'br/public:avm/res/network/vpn-site:0.1.0' = if (enableVpnGateway) { - name: '${commonLayerConfig.name}-vpn-site' - params: { - // Required parameters - name: 'vpn-site-common${uniqueString(resourceGroup().id, 'common')}' - location: location - enableTelemetry: enableTelemetry +@description('Specifies the name of the administrator account of the virtual machine.') +param vmAdminUsername string = enableBastion ? 'azureUser' : newGuid() - // Assign Tags - tags: { - layer: commonLayerConfig.displayName +@description('Specifies the SSH Key or password for the virtual machine. SSH key is recommended.') +@secure() +param vmAdminPasswordOrKey string = enableBastion ? '' : newGuid() + +module manageBlade 'modules/blade_manage.bicep' = { + name: 'manage-blade' + params: { + bladeConfig: { + sectionName: 'manageblade' + displayName: 'Manage Resources' } - virtualWanId: virtualWan.id - addressPrefixes: [ - remoteNetworkPrefix - ] - ipAddress: remoteVpnAddress - } -} + manageLayerConfig: { + machine: { + vmSize: 'Standard_DS3_v2' + imagePublisher: 'Canonical' + imageOffer: 'UbuntuServer' + imageSku: '18.04-LTS' + authenticationType: 'password' + } + bastion: { + skuName: 'Basic' + } + } -module vpnGateway 'br/public:avm/res/network/vpn-gateway:0.1.0' = if (enableVpnGateway) { - name: '${commonLayerConfig.name}-vpn-gateway' - params: { - name: 'vpn-gw-common${uniqueString(resourceGroup().id, 'common')}' location: location enableTelemetry: enableTelemetry - // Assign Tags - tags: { - layer: commonLayerConfig.displayName - } - - virtualHubResourceId: virtualHub.id + workspaceName: logAnalytics.outputs.name + kvName: commonBlade.outputs.keyvaultName - vpnConnections: [ - { - name: 'vpn-connect-common${uniqueString(resourceGroup().id, 'common')}' - connectionBandwidth: 100 - enableBgp: false - enableInternetSecurity: true - enableRateLimiting: false - sharedKey: vpnSharedKey - remoteVpnSiteResourceId: enableVpnGateway ? vpnSite.outputs.resourceId : null - routingWeight: 0 - useLocalAzureIpAddress: false - usePolicyBasedTrafficSelectors: false - vpnConnectionProtocolType: 'IKEv2' - } - ] + // Feature Flags + enableBastion: enableBastion + + vmAdminUsername: vmAdminUsername + vmAdminPasswordOrKey: vmAdminPasswordOrKey + vnetId: networkBlade.outputs.vnetId + vmSubnetId: networkBlade.outputs.vmSubnetId } + dependsOn: [ + networkBlade + commonBlade + ] } -var vnetId = { - new: virtualNetworkNewOrExisting == 'new' ? network.outputs.resourceId : null - existing: resourceId(virtualNetworkResourceGroup, 'Microsoft.Network/virtualNetworks', virtualNetworkName) -} - - -/* - __ ___ ___________ ____ ____ ____ ___ __ __ __ .___________. -| |/ / | ____\ \ / / \ \ / / / \ | | | | | | | | -| ' / | |__ \ \/ / \ \/ / / ^ \ | | | | | | `---| |----` -| < | __| \_ _/ \ / / /_\ \ | | | | | | | | -| . \ | |____ | | \ / / _____ \ | `--' | | `----. | | -|__|\__\ |_______| |__| \__/ /__/ \__\ \______/ |_______| |__| -*/ +//*****************************************************************// +// Partition Blade // +//*****************************************************************// -var vaultDNSZoneName = 'privatelink.vaultcore.azure.net' +@allowed([ + 'CostOptimised' + 'Standard' + 'HighSpec' +]) +@description('The size of the solution') +param solutionTier string = 'CostOptimised' -var vaultSecrets = [ - { - secretName: commonLayerConfig.secrets.tenantId - secretValue: subscription().tenantId - } - { - secretName: commonLayerConfig.secrets.subscriptionId - secretValue: subscription().subscriptionId - } - // Azure AD Secrets - { - secretName: commonLayerConfig.secrets.clientId - secretValue: applicationClientId - } +@description('List of Data Partitions') +param partitions array = [ { - secretName: commonLayerConfig.secrets.applicationPrincipalId - secretValue: applicationClientId + name: 'opendes' } ] -module keyvault 'br/public:avm/res/key-vault/vault:0.3.4' = { - name: '${commonLayerConfig.name}-azure-keyvault' + +module partitionBlade 'modules/blade_partition.bicep' = { + name: 'partition-blade' params: { - name: 'kv-${replace(commonLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, commonLayerConfig.name)}' - location: location - enableTelemetry: enableTelemetry - - // Assign Tags - tags: { - layer: commonLayerConfig.displayName + bladeConfig: { + sectionName: 'partitionblade' + displayName: 'Partition Resources' } - enablePurgeProtection: false - - // Configure RBAC - enableRbacAuthorization: true - roleAssignments: [ - { - roleDefinitionIdOrName: 'Key Vault Reader' - principalId: stampIdentity.outputs.principalId - principalType: 'ServicePrincipal' - } - ] - - // Configure Secrets - secrets: { - secureList: [for secret in vaultSecrets: { - name: secret.secretName - value: secret.secretValue - }] - } - } -} + location: location + workspaceResourceId: logAnalytics.outputs.resourceId -module keyvaultSecrets './modules/keyvault_secrets.bicep' = { - name: '${commonLayerConfig.name}-log-analytics-secrets' - params: { - // Persist Secrets to Vault - keyVaultName: keyvault.outputs.name - workspaceName: logAnalytics.outputs.name - workspaceIdName: commonLayerConfig.secrets.logAnalyticsId - workspaceKeySecretName: commonLayerConfig.secrets.logAnalyticsKey - stampIdName: commonLayerConfig.secrets.stampIdentity - stampIdValue: stampIdentity.outputs.principalId - } -} + kvName: commonBlade.outputs.keyvaultName + subnetId: networkBlade.outputs.aksSubnetId -// Deployment Scripts are not enabled yet for Private Link -// https://github.com/Azure/bicep/issues/6540 -module sshKey './modules/script-sshkeypair/main.bicep' = { - name: '${commonLayerConfig.name}-azure-keyvault-sshkey' - params: { - kvName: keyvault.outputs.name - location: location + enableBlobPublicAccess: enableBlobPublicAccess + enablePrivateLink: enablePrivateLink - useExistingManagedIdentity: true - managedIdentityName: stampIdentity.outputs.name - existingManagedIdentitySubId: subscription().subscriptionId - existingManagedIdentityResourceGroupName:resourceGroup().name + storageDNSZoneId: commonBlade.outputs.storageDNSZoneId + cosmosDNSZoneId: commonBlade.outputs.cosmosDNSZoneId - sshKeyName: 'PrivateLinkSSHKey-' + partitionSize: solutionTier + partitions: partitions } + dependsOn: [ + networkBlade + commonBlade + ] } -module certificates './modules/script-kv-certificate/main.bicep' = { - name: '${commonLayerConfig.name}-azure-keyvault-cert' - params: { - kvName: keyvault.outputs.name - location: location - useExistingManagedIdentity: true - managedIdentityName: stampIdentity.outputs.name - existingManagedIdentitySubId: subscription().subscriptionId - existingManagedIdentityResourceGroupName: resourceGroup().name +//*****************************************************************// +// Service Blade // +//*****************************************************************// +type ingressType = 'Internal' | 'External' | 'Both' +type networkPluginType = 'azure' | 'kubenet' +type clusterNetworkType = { + @description('The type of network plugin to use for the cluster') + networkPlugin: networkPluginType - certificateNames: [ - 'https-certificate' - ] - initialScriptDelay: '0' - validity: 24 - } -} + @description('The type of ingress to use for the cluster') + ingress: ingressType -resource vaultDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (enablePrivateLink) { - name: vaultDNSZoneName - location: 'global' - properties: {} -} + @minLength(9) + @maxLength(18) + @description('The address range to use for services') + serviceCidr: string -module vaultEndpoint './modules/private-endpoint/main.bicep' = if (enablePrivateLink) { - name: '${commonLayerConfig.name}-azure-keyvault-pep' - params: { - resourceName: keyvault.outputs.name - subnetResourceId: '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' + @minLength(9) + @maxLength(18) + @description('The address range to use for the docker bridge') + dockerBridgeCidr: string - groupIds: [ 'vault'] - privateDnsZoneGroup: { - privateDNSResourceIds: [vaultDNSZone.id] - } - serviceResourceId: keyvault.outputs.resourceId - } - dependsOn: [ - network - vaultDNSZone - ] + @minLength(7) + @maxLength(15) + @description('The IP address to reserve for DNS') + dnsServiceIP: string } +type softwareType = { + @description('Feature Flag to Load Software.') + enable: bool + @description('The URL of the software repository') + repository: string + @description('The branch of the software repository') + branch: string +} -/* _______.___________. ______ .______ ___ _______ _______ - / | | / __ \ | _ \ / \ / _____|| ____| - | (----`---| |----`| | | | | |_) | / ^ \ | | __ | |__ - \ \ | | | | | | | / / /_\ \ | | |_ | | __| -.----) | | | | `--' | | |\ \----./ _____ \ | |__| | | |____ -|_______/ |__| \______/ | _| `._____/__/ \__\ \______| |_______| -*/ -@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.') -param enableBlobPublicAccess bool = true -var storageDNSZoneForwarder = 'blob.${environment().suffixes.storage}' -var storageDnsZoneName = 'privatelink.${storageDNSZoneForwarder}' +@description('Cluster Network Properties') +param clusterNetworkProperties clusterNetworkType = { + networkPlugin: enablePodSubnet ? 'azure' : 'kubenet' + ingress: 'Both' + serviceCidr: '172.16.0.0/16' + dockerBridgeCidr: '172.17.0.1/16' + dnsServiceIP: '172.16.0.10' +} -module configStorage './modules/storage-account/main.bicep' = { - name: '${commonLayerConfig.name}-azure-storage' - params: { - name: 'sa${replace(commonLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, commonLayerConfig.name)}' - location: location - - // Assign Tags - tags: { - layer: commonLayerConfig.displayName - } - - // Hook up Diagnostics - diagnosticWorkspaceId: logAnalytics.outputs.resourceId - diagnosticLogsRetentionInDays: 0 - - // Configure Service - sku: commonLayerConfig.storage.sku - tables: commonLayerConfig.storage.tables - shares: commonLayerConfig.storage.shares - - // Apply Security - allowBlobPublicAccess: enableBlobPublicAccess - - // Assign RBAC - roleAssignments: [ - { - roleDefinitionIdOrName: 'Contributor' - principals: [ - { - id: stampIdentity.outputs.principalId - resourceId: stampIdentity.outputs.resourceId - } - ] - principalType: 'ServicePrincipal' - } - ] - - // Hookup Customer Managed Encryption Key - cmekConfiguration: cmekConfiguration - - // Persist Secrets to Vault - keyVaultName: keyvault.outputs.name - storageAccountSecretName: commonLayerConfig.secrets.storageAccountName - storageAccountKeySecretName: commonLayerConfig.secrets.storageAccountKey - } -} - -resource storageDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (enablePrivateLink) { - name: storageDnsZoneName - location: 'global' - properties: {} +@description('Cluster Software Properties') +param clusterSoftwareProperties softwareType = { + enable: true + repository: '' + branch: '' } -module storageEndpoint './modules/private-endpoint/main.bicep' = if (enablePrivateLink) { - name: '${commonLayerConfig.name}-azure-storage-endpoint' - params: { - resourceName: configStorage.outputs.name - subnetResourceId: '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - serviceResourceId: configStorage.outputs.id - groupIds: [ 'blob'] - privateDnsZoneGroup: { - privateDNSResourceIds: [storageDNSZone.id] - } - } - dependsOn: [ - network - storageDNSZone - ] -} - - - -/* - _______ .______ ___ .______ __ __ - / _____|| _ \ / \ | _ \ | | | | -| | __ | |_) | / ^ \ | |_) | | |__| | -| | |_ | | / / /_\ \ | ___/ | __ | -| |__| | | |\ \----./ _____ \ | | | | | | - \______| | _| `._____/__/ \__\ | _| |__| |__| -*/ - -var cosmosDnsZoneName = 'privatelink.documents.azure.com' - -module database './modules/cosmos-db/main.bicep' = { - name: '${commonLayerConfig.name}-cosmos-db' - params: { - resourceName: commonLayerConfig.name - resourceLocation: location - - // Assign Tags - tags: { - layer: commonLayerConfig.displayName - } - - // Hook up Diagnostics - diagnosticWorkspaceId: logAnalytics.outputs.resourceId - diagnosticLogsRetentionInDays: 0 - - // Configure Service - capabilitiesToAdd: [ - 'EnableGremlin' - ] - gremlinDatabases: [ - { - name: commonLayerConfig.database.name - graphs: commonLayerConfig.database.graphs - } - ] - throughput: commonLayerConfig.database.throughput - backupPolicyType: commonLayerConfig.database.backup - - // Assign RBAC - roleAssignments: [ - { - roleDefinitionIdOrName: 'Contributor' - principals: [ - { - id: stampIdentity.outputs.principalId - resourceId: stampIdentity.outputs.resourceId - } - ] - principalType: 'ServicePrincipal' - } - ] - - // Hookup Customer Managed Encryption Key - systemAssignedIdentity: false - userAssignedIdentities: !empty(cmekConfiguration.identityId) ? { - '${stampIdentity.outputs.resourceId}': {} - '${cmekConfiguration.identityId}': {} - } : { - '${stampIdentity.outputs.resourceId}': {} - } - defaultIdentity: !empty(cmekConfiguration.identityId) ? cmekConfiguration.identityId : '' - kvKeyUri: !empty(cmekConfiguration.kvUrl) && !empty(cmekConfiguration.keyName) ? '${cmekConfiguration.kvUrl}/keys/${cmekConfiguration.keyName}' : '' - - // Persist Secrets to Vault - keyVaultName: keyvault.outputs.name - databaseEndpointSecretName: commonLayerConfig.secrets.cosmosEndpoint - databasePrimaryKeySecretName: commonLayerConfig.secrets.cosmosPrimaryKey - databaseConnectionStringSecretName: commonLayerConfig.secrets.cosmosConnectionString - } -} - -resource cosmosDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (enablePrivateLink) { - name: cosmosDnsZoneName - location: 'global' - properties: {} -} - -module graphEndpoint './modules/private-endpoint/main.bicep' = if (enablePrivateLink) { - name: '${commonLayerConfig.name}-cosmos-db-endpoint' - params: { - resourceName: database.outputs.name - subnetResourceId: '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - serviceResourceId: database.outputs.id - groupIds: [ 'sql'] - privateDnsZoneGroup: { - privateDNSResourceIds: [cosmosDNSZone.id] - } - } - dependsOn: [ - network - cosmosDNSZone - ] -} - - - -//*****************************************************************// -// Manage Section // -//*****************************************************************// - -///////////////////////////////// -// Configuration -///////////////////////////////// -var manageLayerConfig = { - name: 'manage' - displayName: 'Manage Resources' - machine: { - vmSize: 'Standard_DS3_v2' - imagePublisher: 'Canonical' - imageOffer: 'UbuntuServer' - imageSku: '18.04-LTS' - authenticationType: 'password' - } -} - -resource existingVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = { - name: keyvault.outputs.name -} - - - -/*.______ ___ _______.___________. __ ______ .__ __. -| _ \ / \ / | || | / __ \ | \ | | -| |_) | / ^ \ | (----`---| |----`| | | | | | | \| | -| _ < / /_\ \ \ \ | | | | | | | | | . ` | -| |_) | / _____ \ .----) | | | | | | `--' | | |\ | -|______/ /__/ \__\ |_______/ |__| |__| \______/ |__| \__| -*/ - -module bastionHost 'br/public:avm/res/network/bastion-host:0.1.0' = if (enableBastion) { - name: '${manageLayerConfig.name}-bastion' - params: { - name: 'bh-${replace(manageLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, manageLayerConfig.name)}' - vNetId: vnetId[virtualNetworkNewOrExisting] - location: location - enableTelemetry: enableTelemetry - } -} - - - -/* -.___ ___. ___ ______ __ __ __ .__ __. _______ -| \/ | / \ / || | | | | | | \ | | | ____| -| \ / | / ^ \ | ,----'| |__| | | | | \| | | |__ -| |\/| | / /_\ \ | | | __ | | | | . ` | | __| -| | | | / _____ \ | `----.| | | | | | | |\ | | |____ -|__| |__| /__/ \__\ \______||__| |__| |__| |__| \__| |_______| -*/ - -@description('Specifies the name of the administrator account of the virtual machine.') -param vmAdminUsername string = enableBastion ? 'azureUser' : newGuid() - -@description('Specifies the SSH Key or password for the virtual machine. SSH key is recommended.') -@secure() -param vmAdminPasswordOrKey string = enableBastion ? '' : newGuid() - -module virtualMachine './modules/virtual_machine.bicep' = if (enableBastion) { - name: 'virtualMachine' - params: { - vmName: 'vm-${replace(manageLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, manageLayerConfig.name)}' - vmSize: manageLayerConfig.machine.vmSize - - // Assign Tags - tags: { - layer: manageLayerConfig.displayName - } - - vmSubnetId: '${vnetId[virtualNetworkNewOrExisting]}/subnets/${vmSubnetName}' - vmAdminPasswordOrKey: empty(vmAdminPasswordOrKey) ? existingVault.getSecret('PrivateLinkSSHKey-public') : vmAdminPasswordOrKey - vmAdminUsername: vmAdminUsername - workspaceName: logAnalytics.outputs.name - authenticationType: empty(vmAdminPasswordOrKey) ? 'sshPublicKey' : 'password' - } - dependsOn: [ - logAnalytics - bastionHost - sshKey - ] -} - - - -//*****************************************************************// -// Partition Section // -//*****************************************************************// - -@allowed([ - 'CostOptimised' - 'Standard' - 'HighSpec' -]) -@description('The Cluster Size') -param clusterSize string = 'CostOptimised' - -@description('List of Data Partitions') -param partitions array = [ - { - name: 'opendes' - } -] - -///////////////////////////////// -// Configuration -///////////////////////////////// -var partitionLayerConfig = { - name: 'partition' - displayName: 'Data Partition Resources' - secrets: { - storageAccountName: 'storage' - storageAccountKey: 'key' - cosmosConnectionString: 'cosmos-connection' - cosmosEndpoint: 'cosmos-endpoint' - cosmosPrimaryKey: 'cosmos-primary-key' - } - storage: { - sku: 'Standard_LRS' - containers: [ - 'legal-service-azure-configuration' - 'osdu-wks-mappings' - 'wdms-osdu' - 'file-staging-area' - 'file-persistent-area' - ] - } - database: { - name: 'osdu-db' - CostOptimised : { - throughput: 2000 - } - Standard: { - throughput: 4000 - } - HighSpec: { - throughput: 12000 - } - backup: 'Continuous' - containers: [ - { - name: 'LegalTag' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'StorageRecord' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'StorageSchema' - kind: 'Hash' - paths: [ - '/kind' - ] - } - { - name: 'TenantInfo' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'UserInfo' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'Authority' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'EntityType' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'SchemaInfo' - kind: 'Hash' - paths: [ - '/partitionId' - ] - } - { - name: 'Source' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'RegisterAction' - kind: 'Hash' - paths: [ - '/dataPartitionId' - ] - } - { - name: 'RegisterDdms' - kind: 'Hash' - paths: [ - '/dataPartitionId' - ] - } - { - name: 'RegisterSubscription' - kind: 'Hash' - paths: [ - '/dataPartitionId' - ] - } - { - name: 'IngestionStrategy' - kind: 'Hash' - paths: [ - '/workflowType' - ] - } - { - name: 'RelationshipStatus' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'MappingInfo' - kind: 'Hash' - paths: [ - '/sourceSchemaKind' - ] - } - { - name: 'FileLocationInfo' - kind: 'Hash' - paths: [ - '/id' - ] - } - { - name: 'WorkflowCustomOperatorInfo' - kind: 'Hash' - paths: [ - '/operatorId' - ] - } - { - name: 'WorkflowV2' - kind: 'Hash' - paths: [ - '/partitionKey' - ] - } - { - name: 'WorkflowRunV2' - kind: 'Hash' - paths: [ - '/partitionKey' - ] - } - { - name: 'WorkflowCustomOperatorV2' - kind: 'Hash' - paths: [ - '/partitionKey' - ] - } - { - name: 'WorkflowTasksSharingInfoV2' - kind: 'Hash' - paths: [ - '/partitionKey' - ] - } - { - name: 'Status' - kind: 'Hash' - paths: [ - '/correlationId' - ] - } - { - name: 'DataSetDetails' - kind: 'Hash' - paths: [ - '/correlationId' - ] - } - ] - } -} - - - -/* -.______ ___ .______ .___________. __ .___________. __ ______ .__ __. _______. -| _ \ / \ | _ \ | || | | || | / __ \ | \ | | / | -| |_) | / ^ \ | |_) | `---| |----`| | `---| |----`| | | | | | | \| | | (----` -| ___/ / /_\ \ | / | | | | | | | | | | | | | . ` | \ \ -| | / _____ \ | |\ \----. | | | | | | | | | `--' | | |\ | .----) | -| _| /__/ \__\ | _| `._____| |__| |__| |__| |__| \______/ |__| \__| |_______/ -*/ - -module partitionStorage './modules/storage-account/main.bicep' = [for (partition, index) in partitions: { - name: '${partitionLayerConfig.name}-azure-storage-${index}' - params: { - #disable-next-line BCP335 BCP332 - name: 'sa${replace('data${index}${substring(uniqueString(partition.name), 0, 6)}', '-', '')}${uniqueString(resourceGroup().id, 'data${index}${substring(uniqueString(partition.name), 0, 6)}')}' - location: location - - // Assign Tags - tags: { - layer: partitionLayerConfig.displayName - partition: partition.name - purpose: 'data' - } - - // Hook up Diagnostics - diagnosticWorkspaceId: logAnalytics.outputs.resourceId - diagnosticLogsRetentionInDays: 0 - - // Apply Security - allowBlobPublicAccess: enableBlobPublicAccess - - // Configure Service - sku: partitionLayerConfig.storage.sku - containers: concat(partitionLayerConfig.storage.containers, [partition.name]) - - // Assign RBAC - roleAssignments: [ - { - roleDefinitionIdOrName: 'Contributor' - principals: [ - { - id: stampIdentity.outputs.principalId - resourceId: stampIdentity.outputs.resourceId - } - ] - principalType: 'ServicePrincipal' - } - ] - - // Hookup Customer Managed Encryption Key - cmekConfiguration: cmekConfiguration - - // Persist Secrets to Vault - keyVaultName: keyvault.outputs.name - storageAccountSecretName: '${partition.name}-${partitionLayerConfig.secrets.storageAccountName}' - storageAccountKeySecretName: '${partition.name}-${partitionLayerConfig.secrets.storageAccountKey}' - } -}] - -module partitionStorageEndpoint './modules/private-endpoint/main.bicep' = [for (partition, index) in partitions: if (enablePrivateLink) { - name: '${partitionLayerConfig.name}-azure-storage-endpoint-${index}' - params: { - resourceName: partitionStorage[index].outputs.name - subnetResourceId: '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - serviceResourceId: partitionStorage[index].outputs.id - groupIds: [ 'blob'] - privateDnsZoneGroup: { - privateDNSResourceIds: [storageDNSZone.id] - } - } - dependsOn: [ - network - storageDNSZone - ] -}] - -module partitionDb './modules/cosmos-db/main.bicep' = [for (partition, index) in partitions: { - name: '${partitionLayerConfig.name}-cosmos-db-${index}' - params: { - #disable-next-line BCP335 - resourceName: 'data${index}${substring(uniqueString(partition.name), 0, 6)}' - resourceLocation: location - - // Assign Tags - tags: { - layer: partitionLayerConfig.displayName - partition: partition.name - purpose: 'data' - } - - // Hook up Diagnostics - diagnosticWorkspaceId: logAnalytics.outputs.resourceId - diagnosticLogsRetentionInDays: 0 - - // Configure Service - sqlDatabases: [ - { - name: partitionLayerConfig.database.name - containers: partitionLayerConfig.database.containers - } - ] - maxThroughput: partitionLayerConfig.database[clusterSize].throughput - backupPolicyType: partitionLayerConfig.database.backup - - // Assign RBAC - roleAssignments: [ - { - roleDefinitionIdOrName: 'Contributor' - principals: [ - { - id: stampIdentity.outputs.principalId - resourceId: stampIdentity.outputs.resourceId - } - ] - principalType: 'ServicePrincipal' - } - ] - - // Hookup Customer Managed Encryption Key - systemAssignedIdentity: false - userAssignedIdentities: !empty(cmekConfiguration.identityId) ? { - '${stampIdentity.outputs.resourceId}': {} - '${cmekConfiguration.identityId}': {} - } : { - '${stampIdentity.outputs.resourceId}': {} - } - defaultIdentity: !empty(cmekConfiguration.identityId) ? cmekConfiguration.identityId : '' - kvKeyUri: !empty(cmekConfiguration.kvUrl) && !empty(cmekConfiguration.keyName) ? '${cmekConfiguration.kvUrl}/keys/${cmekConfiguration.keyName}' : '' - - // Persist Secrets to Vault - keyVaultName: keyvault.outputs.name - databaseEndpointSecretName: '${partition.name}-${partitionLayerConfig.secrets.cosmosEndpoint}' - databasePrimaryKeySecretName: '${partition.name}-${partitionLayerConfig.secrets.cosmosPrimaryKey}' - databaseConnectionStringSecretName: '${partition.name}-${partitionLayerConfig.secrets.cosmosConnectionString}' - } -}] - -module partitionDbEndpoint './modules/private-endpoint/main.bicep' = [for (partition, index) in partitions: if (enablePrivateLink) { - name: '${partitionLayerConfig.name}-cosmos-db-endpoint-${index}' - params: { - resourceName: partitionDb[index].outputs.name - subnetResourceId: '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - serviceResourceId: partitionDb[index].outputs.id - groupIds: [ 'sql'] - privateDnsZoneGroup: { - privateDNSResourceIds: [cosmosDNSZone.id] - } - } - dependsOn: [ - network - cosmosDNSZone - ] -}] - - - -//*****************************************************************// -// Service Section // -//*****************************************************************// -@description('Feature Flag to create software config map.') -var enableConfigMap = true - -@description('Feature Flag to Load Software.') -var enableSoftwareLoad = true - -@description('Software GIT Repository URL') -param softwareRepository string = 'https://github.com/azure/osdu-developer' - -@description('Software GIT Repository Branch') -param softwareBranch string = 'main' - -@allowed([ - 'Internal' - 'External' - 'Both' -]) -@description('The Cluster Ingress Mode') -param clusterIngress string = 'Both' - @description('Optional: Specify the AD Users and/or Groups that can manage the cluster.') param clusterAdminIds array = [] -///////////////////////////////// -// Configuration -///////////////////////////////// - -var serviceLayerConfig = { - name: 'service' - displayName: 'Service Resources' - cluster: { - aksVersion: '1.28' - meshVersion: 'asm-1-18' - networkPlugin: enablePodSubnet ? 'azure' : 'kubenet' - } - gitops: { - name: 'flux-system' - url: softwareRepository - branch: softwareBranch - components: './stamp/components' - applications: './stamp/applications' - } - imageList: { - None: [] - M22: [ - 'community.opengroup.org:5555/osdu/platform/system/partition/partition-v0-24-0:latest' - 'community.opengroup.org:5555/osdu/platform/security-and-compliance/entitlements/entitlements-v0-24-0:latest' - 'community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/legal-v0-24-0:latest' - 'community.opengroup.org:5555/osdu/platform/system/schema-service/schema-service-release-0-24:latest' - 'community.opengroup.org:5555/osdu/platform/system/storage/storage-v0-24-0:latest' - 'community.opengroup.org:5555/osdu/platform/system/file/file-v0-24-0:latest' - 'community.opengroup.org:5555/osdu/platform/system/indexer-service/indexer-service-v0-24-0:latest' - 'community.opengroup.org:5555/osdu/platform/system/search-service/search-service-v0-24-0:latest' - ] - } -} - - -/* - - __ ___ __ __ .______ _______ .______ .__ __. _______ .___________. _______ _______. -| |/ / | | | | | _ \ | ____|| _ \ | \ | | | ____|| || ____| / | -| ' / | | | | | |_) | | |__ | |_) | | \| | | |__ `---| |----`| |__ | (----` -| < | | | | | _ < | __| | / | . ` | | __| | | | __| \ \ -| . \ | `--' | | |_) | | |____ | |\ \----.| |\ | | |____ | | | |____.----) | -|__|\__\ \______/ |______/ |_______|| _| `._____||__| \__| |_______| |__| |_______|_______/ -*/ - -module cluster './modules/aks_cluster.bicep' = { - name: '${serviceLayerConfig.name}-aks-cluster' - params: { - // Basic Details - resourceName: serviceLayerConfig.name - location: location - aksVersion: serviceLayerConfig.cluster.aksVersion - aad_tenant_id: subscription().tenantId - clusterSize: clusterSize - networkPlugin: serviceLayerConfig.cluster.networkPlugin - - // Assign Tags - tags: { - layer: serviceLayerConfig.displayName - } - - // Configure Linking Items - aksSubnetId: virtualNetworkNewOrExisting != 'new' ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' : '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - aksPodSubnetId: virtualNetworkNewOrExisting != 'new' && enablePodSubnet ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${podSubnetName}' : null - identityId: stampIdentity.outputs.resourceId - workspaceId: logAnalytics.outputs.resourceId - - // Configure VNET Injection - serviceCidr: serviceCidr - dnsServiceIP: dnsServiceIP - dockerBridgeCidr: dockerBridgeCidr - - // Configure Istio - serviceMeshProfile: 'Istio' - istioRevision: serviceLayerConfig.cluster.meshVersion - istioIngressGatewayMode: clusterIngress - - // Configure Add Ons - enable_aad: empty(clusterAdminIds) == true ? false : true - admin_ids: clusterAdminIds - workloadIdentityEnabled: true - oidcIssuer: true - keyvaultEnabled: true - fluxGitOpsAddon: true - enableImageCleaner: true - fileCSIDriver: true - blobCSIDriver: true - azurepolicy: 'audit' - } -} - -///////////////// -// Elastic Configuration -///////////////// -var elasticPoolPresets = { - // 4 vCPU, 15 GiB RAM, 28 GiB SSD, (12800) IOPS, Ephemeral OS Disk - CostOptimised : { - vmSize: 'Standard_DS3_v2' - } - // 8 vCPU, 28 GiB RAM, 56 GiB SSD, (32000) IOPS, Ephemeral OS Disk - Standard : { - vmSize: 'Standard_DS4_v2' - } - // 16 vCPU, 56 GiB RAM, 112 GiB SSD, (64000) IOPS, Ephemeral OS Disk - HighSpec : { - vmSize: 'Standard_DS5_v2' - } -} - -module pool1 './modules/aks_agent_pool.bicep' = { - name: '${serviceLayerConfig.name}-pool1' - params: { - AksName: cluster.outputs.aksClusterName - PoolName: 'poolz1' - agentVMSize: elasticPoolPresets[clusterSize].vmSize - agentCount: 2 - agentCountMax: 4 - availabilityZones: [ - '1' - ] - subnetId: virtualNetworkNewOrExisting != 'new' ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' : '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - podSubnetId: virtualNetworkNewOrExisting != 'new' && enablePodSubnet ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${podSubnetName}' : '' - nodeTaints: ['app=cluster:NoSchedule'] - nodeLabels: { - app: 'cluster' - } - } -} - -module pool2 './modules/aks_agent_pool.bicep' = { - name: '${serviceLayerConfig.name}-pool2' - params: { - AksName: cluster.outputs.aksClusterName - PoolName: 'poolz2' - agentVMSize: elasticPoolPresets[clusterSize].vmSize - agentCount: 2 - agentCountMax: 4 - availabilityZones: [ - '2' - ] - subnetId: virtualNetworkNewOrExisting != 'new' ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' : '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - podSubnetId: virtualNetworkNewOrExisting != 'new' && enablePodSubnet ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${podSubnetName}' : '' - nodeTaints: ['app=cluster:NoSchedule'] - nodeLabels: { - app: 'cluster' - } - } -} - -module pool3 './modules/aks_agent_pool.bicep' = { - name: '${serviceLayerConfig.name}-pool3' +module serviceBlade 'modules/blade_service.bicep' = { + name: 'service-blade' params: { - AksName: cluster.outputs.aksClusterName - PoolName: 'poolz3' - agentVMSize: elasticPoolPresets[clusterSize].vmSize - agentCount: 2 - agentCountMax: 4 - availabilityZones: [ - '3' - ] - subnetId: virtualNetworkNewOrExisting != 'new' ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' : '${vnetId[virtualNetworkNewOrExisting]}/subnets/${aksSubnetName}' - podSubnetId: virtualNetworkNewOrExisting != 'new' && enablePodSubnet ? '${vnetId[virtualNetworkNewOrExisting]}/subnets/${podSubnetName}' : '' - nodeTaints: ['app=cluster:NoSchedule'] - nodeLabels: { - app: 'cluster' + bladeConfig: { + sectionName: 'serviceblade' + displayName: 'Service Resources' } - } -} - -///////////////// -// Workload Identity Federated Credentials -///////////////// -module appIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.1.0' = { - name: '${serviceLayerConfig.name}-user-managed-identity' - params: { - // Required parameters - name: 'id-${replace(serviceLayerConfig.name, '-', '')}${uniqueString(resourceGroup().id, serviceLayerConfig.name)}' location: location enableTelemetry: enableTelemetry - // Only support 1. https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-considerations#concurrent-updates-arent-supported-user-assigned-managed-identities - federatedIdentityCredentials: [{ - audiences: [ - 'api://AzureADTokenExchange' - ] - issuer: cluster.outputs.aksOidcIssuerUrl - name: 'federated-ns_default' - subject: 'system:serviceaccount:default:workload-identity-sa' - }] - - roleAssignments: [ - { - roleDefinitionIdOrName: 'Managed Identity Operator' - principalId: stampIdentity.outputs.principalId - principalType: 'ServicePrincipal' - } - ] - - // Assign Tags - tags: { - layer: serviceLayerConfig.displayName - } - } -} - -// Federated Credentials have to be sequentially added. Ensure depends on. -module federatedCredsDevSample './modules/federated_identity.bicep' = { - name: '${serviceLayerConfig.name}-federated-cred-ns_dev-sample' - params: { - name: 'federated-ns_dev-sample' - audiences: [ - 'api://AzureADTokenExchange' - ] - issuer: cluster.outputs.aksOidcIssuerUrl - userAssignedIdentityName: appIdentity.outputs.name - subject: 'system:serviceaccount:dev-sample:workload-identity-sa' - } - dependsOn: [ - appIdentity - ] -} - -module federatedCredsConfigMaps './modules/federated_identity.bicep' = { - name: '${serviceLayerConfig.name}-federated-cred-ns_config-maps' - params: { - name: 'federated-ns_azappconfig-system' - audiences: [ - 'api://AzureADTokenExchange' - ] - issuer: cluster.outputs.aksOidcIssuerUrl - userAssignedIdentityName: appIdentity.outputs.name - subject: 'system:serviceaccount:azappconfig-system:az-appconfig-k8s-provider' - } - dependsOn: [ - federatedCredsDevSample - ] -} - -module appRoleAssignments './modules/app_assignments.bicep' = { - name: '${serviceLayerConfig.name}-user-managed-identity-rbac' - params: { - identityprincipalId: appIdentity.outputs.principalId - kvName: keyvault.outputs.name - storageName: configStorage.outputs.name - } - dependsOn: [ - federatedCredsConfigMaps - ] -} - -module appRoleAssignments2 './modules/app_assignments.bicep' = [for (partition, index) in partitions: { - name: '${serviceLayerConfig.name}-user-managed-identity-rbac-${partition.name}' - params: { - identityprincipalId: appIdentity.outputs.principalId - storageName: partitionStorage[index].outputs.name - } - dependsOn: [ - federatedCredsDevSample - ] -}] - -///////////////// -// Helm Charts -///////////////// -module helmAppConfigProvider './modules/aks-run-command/main.bicep' = { - name: '${serviceLayerConfig.name}-helm-appconfig-provider' - params: { - aksName: cluster.outputs.aksClusterName - location: location + enableSoftwareLoad: clusterSoftwareProperties.enable - newOrExistingManagedIdentity: 'existing' + workspaceResourceId: logAnalytics.outputs.resourceId + identityId: enableVnetInjection ? networkBlade.outputs.networkConfiguration.identityId : stampIdentity.outputs.resourceId managedIdentityName: stampIdentity.outputs.name - existingManagedIdentitySubId: subscription().subscriptionId - existingManagedIdentityResourceGroupName:resourceGroup().name - - commands: [ - 'helm install azureappconfiguration.kubernetesprovider oci://mcr.microsoft.com/azure-app-configuration/helmchart/kubernetes-provider --namespace azappconfig-system --create-namespace' - ] - } -} - - - -/* - ___ .______ .______ ______ ______ .__ __. _______ __ _______ - / \ | _ \ | _ \ / | / __ \ | \ | | | ____|| | / _____| - / ^ \ | |_) | | |_) | | ,----'| | | | | \| | | |__ | | | | __ - / /_\ \ | ___/ | ___/ | | | | | | | . ` | | __| | | | | |_ | - / _____ \ | | | | | `----.| `--' | | |\ | | | | | | |__| | -/__/ \__\ | _| | _| \______| \______/ |__| \__| |__| |__| \______| -*/ - -var appSettings = [ - { - name: 'Settings:Message' - value: 'Hello from App Configuration' - contentType: 'text/plain' - label: 'configmap-devsample' - } - { - name: 'Settings:StorageAccountName' - value: partitionStorage[0].outputs.name - contentType: 'text/plain' - label: 'configmap-devsample' - } -] - -module app_config 'modules/app-configuration/main.bicep' = { - name: '${serviceLayerConfig.name}-appconfig' - params: { - resourceName: serviceLayerConfig.name - location: location - tags: { - layer: serviceLayerConfig.displayName - } - - // Add Role Assignment - roleAssignments: [ - { - roleDefinitionIdOrName: 'App Configuration Data Reader' - principalIds: [ - appIdentity.outputs.principalId - ] - principalType: 'ServicePrincipal' - } - ] - - // Add Configuration - keyValues: concat(appSettings) - } - dependsOn: [ - appRoleAssignments - appRoleAssignments2 - ] -} - -@description('The name of the azure keyvault.') -output ENV_CONFIG_ENDPOINT string = app_config.outputs.endpoint - -//--------------Config Map--------------- -// SecretProviderClass --> tenantId, clientId, keyvaultName -// ServiceAccount --> tenantId, clientId -// AzureAppConfigurationProvider --> tenantId, clientId, configEndpoint, keyvaultUri -var configMaps = { - appConfigTemplate: ''' -values.yaml: | - serviceAccount: - create: false - name: "workload-identity-sa" - azure: - tenantId: {0} - clientId: {1} - configEndpoint: {2} - keyvaultUri: {3} - keyvaultName: {4} - ''' -} - -module appConfigMap './modules/aks-config-map/main.bicep' = if (enableConfigMap) { - name: '${serviceLayerConfig.name}-cluster-appconfig-configmap' - params: { - aksName: cluster.outputs.aksClusterName - location: location - name: 'config-map-values' - namespace: 'default' - fileData: [ - format(configMaps.appConfigTemplate, - subscription().tenantId, - appIdentity.outputs.clientId, - app_config.outputs.endpoint, - keyvault.outputs.uri, - keyvault.outputs.name) - ] - } -} - - - -/* _______ __ .___________. ______ .______ _______. - / _____|| | | | / __ \ | _ \ / | -| | __ | | `---| |----`| | | | | |_) | | (----` -| | |_ | | | | | | | | | | ___/ \ \ -| |__| | | | | | | `--' | | | .----) | - \______| |__| |__| \______/ | _| |_______/ -*/ - -//--------------Flux Config--------------- -module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-configuration:0.3.1' = if(enableSoftwareLoad) { - name: '${serviceLayerConfig.name}-cluster-gitops' - params: { - name: serviceLayerConfig.gitops.name - location: location - namespace: cluster.outputs.fluxReleaseNamespace - clusterName: cluster.outputs.aksClusterName - scope: 'cluster' - sourceKind: 'GitRepository' - gitRepository: { - url: serviceLayerConfig.gitops.url - timeoutInSeconds: 180 - syncIntervalInSeconds: 300 - repositoryRef: { - branch: serviceLayerConfig.gitops.branch - } - } - kustomizations: { - components: { - path: serviceLayerConfig.gitops.components - timeoutInSeconds: 300 - syncIntervalInSeconds: 300 - retryIntervalInSeconds: 300 - prune: true - } - applications: { - path: serviceLayerConfig.gitops.applications - dependsOn: [ - 'components' - ] - timeoutInSeconds: 300 - syncIntervalInSeconds: 300 - retryIntervalInSeconds: 300 - prune: true - } - } + kvName: commonBlade.outputs.keyvaultName + kvUri: commonBlade.outputs.keyvaultUri + storageName: commonBlade.outputs.storageAccountName + partitionStorageNames: partitionBlade.outputs.partitionStorageNames + + aksSubnetId: networkBlade.outputs.aksSubnetId + podSubnetId: enablePodSubnet ? networkBlade.outputs.podSubnetId : '' + clusterSize: solutionTier + clusterIngress: clusterNetworkProperties.ingress + clusterAdminIds: clusterAdminIds + serviceCidr: clusterNetworkProperties.serviceCidr + dnsServiceIP: clusterNetworkProperties.dnsServiceIP + dockerBridgeCidr: clusterNetworkProperties.dockerBridgeCidr + networkPlugin: clusterNetworkProperties.networkPlugin + + softwareBranch: clusterSoftwareProperties.branch + softwareRepository: clusterSoftwareProperties.repository } dependsOn: [ - app_config - appConfigMap - pool1 - pool2 - pool3 + networkBlade + commonBlade + partitionBlade ] } -//ACSCII Art link : https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=Star%20Wars&text=changeme +// //ACSCII Art link : https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=Star%20Wars&text=changeme diff --git a/bicep/main.parameters.json b/bicep/main.parameters.json index 44adde38..6fb822d7 100644 --- a/bicep/main.parameters.json +++ b/bicep/main.parameters.json @@ -5,32 +5,68 @@ "applicationClientId": { "value": "${AZURE_CLIENT_ID}" }, - "enablePodSubnet": { - "value": "${ENABLE_POD_SUBNET}" - }, - "enableVpnGateway": { - "value": "${ENABLE_VPN_GATEWAY}" - }, + "enableVnetInjection": { + "value": "${ENABLE_VNET_INJECTION}" + }, "enableBastion": { "value": "${ENABLE_BASTION}" }, + "enablePodSubnet": { + "value": "${ENABLE_POD_SUBNET}" + }, "enableBlobPublicAccess": { "value": "${ENABLE_BLOB_PUBLIC_ACCESS}" }, - "vpnSharedKey": { - "value": "${VPN_SHARED_KEY}" - }, - "remoteVpnAddress": { - "value": "${REMOTE_VPN_ADDRESS}" - }, - "remoteNetworkPrefix": { - "value": "${REMOTE_NETWORK_PREFIX}" - }, "softwareRepository": { "value": "${SOFTWARE_REPOSITORY}" }, "softwareBranch": { "value": "${SOFTWARE_BRANCH}" + }, + "virtualNetworkResourceGroup": { + "value": "${VIRTUAL_NETWORK_GROUP}" + }, + "virtualNetworkName": { + "value": "${VIRTUAL_NETWORK_NAME}" + }, + "virtualNetworkAddressPrefix": { + "value": "${VIRTUAL_NETWORK_PREFIX}" + }, + "aksSubnetName": { + "value": "${AKS_SUBNET_NAME}" + }, + "aksSubnetAddressPrefix": { + "value": "${AKS_SUBNET_PREFIX}" + }, + "podSubnetName": { + "value": "${POD_SUBNET_NAME}" + }, + "podSubnetAddressPrefix": { + "value": "${POD_SUBNET_PREFIX}" + }, + "vnetConfiguration": { + "value": { + "group": "${VIRTUAL_NETWORK_GROUP}", + "name": "${VIRTUAL_NETWORK_NAME}", + "prefix": "${VIRTUAL_NETWORK_PREFIX}", + "aksSubnet": { + "name": "${AKS_SUBNET_NAME}", + "prefix": "${AKS_SUBNET_PREFIX}" + }, + "podSubnet": { + "name": "${POD_SUBNET_NAME}", + "prefix": "${POD_SUBNET_PREFIX}" + }, + "vmSubnet": { + "name": "${VM_SUBNET_NAME}", + "prefix": "${VM_SUBNET_PREFIX}" + }, + "bastionSubnet": { + "name": "${BASTION_SUBNET_NAME}", + "prefix": "${BASTION_SUBNET_PREFIX}" + }, + "identityId": "${VIRTUAL_NETWORK_IDENTITY}" + } } } } \ No newline at end of file diff --git a/bicep/modules/blade_common.bicep b/bicep/modules/blade_common.bicep new file mode 100644 index 00000000..3138ce59 --- /dev/null +++ b/bicep/modules/blade_common.bicep @@ -0,0 +1,360 @@ +///////////////// +// Common Blade +///////////////// + +type bladeSettings = { + @description('The name of the section name') + sectionName: string + @description('The display name of the section') + displayName: string +} + + +@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.') +param enableBlobPublicAccess bool + +@description('The location of resources to deploy') +param location string + +@description('Feature Flag to Enable Telemetry') +param enableTelemetry bool + +@description('The configuration for the blade section.') +param bladeConfig bladeSettings + +@description('Feature Flag to Enable Private Link') +param enablePrivateLink bool + +@description('The list of secrets to persist to the Key Vault') +param vaultSecrets array + +@description('The workspace resource Id for diagnostics') +param workspaceResourceId string + +@description('The Diagnostics Workspace Name') +param workspaceName string + +@description('The KeyVault Secret Name for the Workspace Id') +param workspaceIdName string + +@description('The KeyVault Secret Name for the Workspace Key') +param workspaceKeySecretName string + +@description('The managed identity name for deployment scripts') +param deploymentScriptIdentity string + +@description('The subnet id for Private Endpoints') +param subnetId string + +@description('Optional. Customer Managed Encryption Key.') +param cmekConfiguration object = { + kvUrl: '' + keyName: '' + identityId: '' +} + +var commonLayerConfig = { + secrets: { + tenantId: 'tenant-id' + subscriptionId: 'subscription-id' + registryName: 'container-registry' + applicationId: 'aad-client-id' + clientId: 'app-dev-sp-username' + clientSecret: 'app-dev-sp-password' + applicationPrincipalId: 'app-dev-sp-id' + stampIdentity: 'osdu-identity-id' + storageAccountName: 'common-storage' + storageAccountKey: 'common-storage-key' + cosmosConnectionString: 'graph-db-connection' + cosmosEndpoint: 'graph-db-endpoint' + cosmosPrimaryKey: 'graph-db-primary-key' + logAnalyticsId: 'log-workspace-id' + logAnalyticsKey: 'log-workspace-key' + } + storage: { + sku: 'Standard_LRS' + tables: [ + 'partitionInfo' + ] + shares: [ + 'crs' + 'crs-conversion' + 'unit' + 'sample-share' + ] + } + database: { + name: 'graph-db' + throughput: 2000 + backup: 'Continuous' + graphs: [ + { + name: 'Entitlements' + automaticIndexing: true + partitionKeyPaths: [ + '/dataPartitionId' + ] + } + ] + } +} + +/* + __ ___ ___________ ____ ____ ____ ___ __ __ __ .___________. +| |/ / | ____\ \ / / \ \ / / / \ | | | | | | | | +| ' / | |__ \ \/ / \ \/ / / ^ \ | | | | | | `---| |----` +| < | __| \_ _/ \ / / /_\ \ | | | | | | | | +| . \ | |____ | | \ / / _____ \ | `--' | | `----. | | +|__|\__\ |_______| |__| \__/ /__/ \__\ \______/ |_______| |__| +*/ + +var name = 'kv-${replace(bladeConfig.sectionName, '-', '')}${uniqueString(resourceGroup().id, bladeConfig.sectionName)}' + +module keyvault 'br/public:avm/res/key-vault/vault:0.3.4' = { + name: '${bladeConfig.sectionName}-keyvault' + params: { + name: length(name) > 24 ? substring(name, 0, 24) : name + location: location + enableTelemetry: enableTelemetry + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + enablePurgeProtection: false + + // Configure RBAC + enableRbacAuthorization: true + + // Configure Secrets + secrets: { + secureList: [for secret in vaultSecrets: { + name: secret.secretName + value: secret.secretValue + }] + } + } +} + +module keyvaultSecrets './keyvault_secrets.bicep' = { + name: '${bladeConfig.sectionName}-diag-secrets' + params: { + // Persist Secrets to Vault + keyVaultName: keyvault.outputs.name + workspaceName: workspaceName + workspaceIdName: workspaceIdName + workspaceKeySecretName: workspaceKeySecretName + } +} + +// Deployment Scripts are not enabled yet for Private Link +// https://github.com/Azure/bicep/issues/6540 +module sshKey './script-sshkeypair/main.bicep' = { + name: '${bladeConfig.sectionName}-keyvault-sshkey' + params: { + kvName: keyvault.outputs.name + location: location + + useExistingManagedIdentity: true + managedIdentityName: deploymentScriptIdentity + existingManagedIdentitySubId: subscription().subscriptionId + existingManagedIdentityResourceGroupName:resourceGroup().name + + sshKeyName: 'PrivateLinkSSHKey-' + } +} + +module certificates './script-kv-certificate/main.bicep' = { + name: '${bladeConfig.sectionName}-keyvault-cert' + params: { + kvName: keyvault.outputs.name + location: location + + useExistingManagedIdentity: true + managedIdentityName: deploymentScriptIdentity + existingManagedIdentitySubId: subscription().subscriptionId + existingManagedIdentityResourceGroupName: resourceGroup().name + + certificateNames: [ + 'https-certificate' + ] + initialScriptDelay: '0' + validity: 24 + } +} + +resource vaultDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (enablePrivateLink) { + name: 'privatelink.vaultcore.azure.net' + location: 'global' + properties: {} +} + +module vaultEndpoint './private-endpoint/main.bicep' = if (enablePrivateLink) { + name: '${bladeConfig.sectionName}-keyvault-pep' + params: { + resourceName: keyvault.outputs.name + subnetResourceId: subnetId + + groupIds: [ 'vault'] + privateDnsZoneGroup: { + privateDNSResourceIds: [vaultDNSZone.id] + } + serviceResourceId: keyvault.outputs.resourceId + } + dependsOn: [ + vaultDNSZone + ] +} + +/* _______.___________. ______ .______ ___ _______ _______ + / | | / __ \ | _ \ / \ / _____|| ____| + | (----`---| |----`| | | | | |_) | / ^ \ | | __ | |__ + \ \ | | | | | | | / / /_\ \ | | |_ | | __| +.----) | | | | `--' | | |\ \----./ _____ \ | |__| | | |____ +|_______/ |__| \______/ | _| `._____/__/ \__\ \______| |_______| +*/ + + + +var storageDNSZoneForwarder = 'blob.${environment().suffixes.storage}' +var storageDnsZoneName = 'privatelink.${storageDNSZoneForwarder}' + +module configStorage './storage-account/main.bicep' = { + name: '${bladeConfig.sectionName}-storage' + params: { + name: 'sa${replace(bladeConfig.sectionName, '-', '')}${uniqueString(resourceGroup().id, bladeConfig.sectionName)}' + location: location + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + // Hook up Diagnostics + diagnosticWorkspaceId: workspaceResourceId + diagnosticLogsRetentionInDays: 0 + + // Configure Service + sku: commonLayerConfig.storage.sku + tables: commonLayerConfig.storage.tables + shares: commonLayerConfig.storage.shares + + // Apply Security + allowBlobPublicAccess: enableBlobPublicAccess + + // Hookup Customer Managed Encryption Key + cmekConfiguration: cmekConfiguration + + // Persist Secrets to Vault + keyVaultName: keyvault.outputs.name + storageAccountSecretName: commonLayerConfig.secrets.storageAccountName + storageAccountKeySecretName: commonLayerConfig.secrets.storageAccountKey + } +} + +resource storageDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (enablePrivateLink) { + name: storageDnsZoneName + location: 'global' + properties: {} +} + +module storageEndpoint './private-endpoint/main.bicep' = if (enablePrivateLink) { + name: '${bladeConfig.sectionName}-storage-endpoint' + params: { + resourceName: configStorage.outputs.name + subnetResourceId: subnetId + serviceResourceId: configStorage.outputs.id + groupIds: [ 'blob'] + privateDnsZoneGroup: { + privateDNSResourceIds: [storageDNSZone.id] + } + } + dependsOn: [ + storageDNSZone + ] +} + + +/* + _______ .______ ___ .______ __ __ + / _____|| _ \ / \ | _ \ | | | | +| | __ | |_) | / ^ \ | |_) | | |__| | +| | |_ | | / / /_\ \ | ___/ | __ | +| |__| | | |\ \----./ _____ \ | | | | | | + \______| | _| `._____/__/ \__\ | _| |__| |__| +*/ + +var cosmosDnsZoneName = 'privatelink.documents.azure.com' + +module database './cosmos-db/main.bicep' = { + name: '${bladeConfig.sectionName}-cosmos-db' + params: { + resourceName: bladeConfig.sectionName + resourceLocation: location + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + // Hook up Diagnostics + diagnosticWorkspaceId: workspaceResourceId + diagnosticLogsRetentionInDays: 0 + + // Configure Service + capabilitiesToAdd: [ + 'EnableGremlin' + ] + gremlinDatabases: [ + { + name: commonLayerConfig.database.name + graphs: commonLayerConfig.database.graphs + } + ] + throughput: commonLayerConfig.database.throughput + backupPolicyType: commonLayerConfig.database.backup + + // Hookup Customer Managed Encryption Key + systemAssignedIdentity: false + userAssignedIdentities: !empty(cmekConfiguration.identityId) ? { + '${cmekConfiguration.identityId}': {} + } : {} + defaultIdentity: !empty(cmekConfiguration.identityId) ? cmekConfiguration.identityId : '' + kvKeyUri: !empty(cmekConfiguration.kvUrl) && !empty(cmekConfiguration.keyName) ? '${cmekConfiguration.kvUrl}/keys/${cmekConfiguration.keyName}' : '' + + // Persist Secrets to Vault + keyVaultName: keyvault.outputs.name + databaseEndpointSecretName: commonLayerConfig.secrets.cosmosEndpoint + databasePrimaryKeySecretName: commonLayerConfig.secrets.cosmosPrimaryKey + databaseConnectionStringSecretName: commonLayerConfig.secrets.cosmosConnectionString + } +} + +resource cosmosDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (enablePrivateLink) { + name: cosmosDnsZoneName + location: 'global' + properties: {} +} + +module graphEndpoint './private-endpoint/main.bicep' = if (enablePrivateLink) { + name: '${bladeConfig.sectionName}-cosmos-db-endpoint' + params: { + resourceName: database.outputs.name + subnetResourceId: subnetId + serviceResourceId: database.outputs.id + groupIds: [ 'sql'] + privateDnsZoneGroup: { + privateDNSResourceIds: [cosmosDNSZone.id] + } + } + dependsOn: [ + cosmosDNSZone + ] +} + +output keyvaultName string = keyvault.outputs.name +output keyvaultUri string = keyvault.outputs.uri +output storageAccountName string = configStorage.outputs.name +output storageDNSZoneId string = storageDNSZone.id +output cosmosDNSZoneId string = cosmosDNSZone.id diff --git a/bicep/modules/blade_manage.bicep b/bicep/modules/blade_manage.bicep new file mode 100644 index 00000000..2e1893c8 --- /dev/null +++ b/bicep/modules/blade_manage.bicep @@ -0,0 +1,126 @@ +//*****************************************************************// +// Manage Section // +//*****************************************************************// + +type bladeSettings = { + @description('The name of the section name') + sectionName: string + @description('The display name of the section') + displayName: string +} + +type manageSettings = { + @description('The settings for the virtual machine') + machine: machineSettings + @description('The settings for the bastion') + bastion: bastionSettings +} + +type machineSettings = { + @description('The size of the virtual machine') + vmSize: string + @description('The publisher of the image') + imagePublisher: string + @description('The offer of the image') + imageOffer: string + @description('The SKU of the image') + imageSku: string + @description('The authentication type of the virtual machine') + authenticationType: string +} + +type bastionSkuType = 'Basic' | 'Standard' + +type bastionSettings = { + @description('The name of the SKU') + skuName: bastionSkuType +} + + +@description('The configuration for the blade section.') +param bladeConfig bladeSettings + +@description('The location of resources to deploy') +param location string + +@description('Feature Flag to Enable Telemetry') +param enableTelemetry bool = false + + +@description('Specifies the name of the administrator account of the virtual machine.') +param vmAdminUsername string + +@description('Specifies the SSH Key or password for the virtual machine. SSH key is recommended.') +@secure() +param vmAdminPasswordOrKey string + +@description('Feature Flag to Enable Bastion') +param enableBastion bool + +@description('The name of the Key Vault where the secret exists') +param kvName string + +@description('The Id of the virtual network') +param vnetId string + +@description('The Id of the subnet for the virtual machine') +param vmSubnetId string + +@description('The workspace name for diagnostics') +param workspaceName string + +@description('The configuration for the manage section.') +param manageLayerConfig manageSettings + + +/*.______ ___ _______.___________. __ ______ .__ __. +| _ \ / \ / | || | / __ \ | \ | | +| |_) | / ^ \ | (----`---| |----`| | | | | | | \| | +| _ < / /_\ \ \ \ | | | | | | | | | . ` | +| |_) | / _____ \ .----) | | | | | | `--' | | |\ | +|______/ /__/ \__\ |_______/ |__| |__| \______/ |__| \__| +*/ + +module bastionHost 'br/public:avm/res/network/bastion-host:0.1.1' = if (enableBastion) { + name: '${bladeConfig.sectionName}-bastion' + params: { + name: 'bh-${replace(bladeConfig.sectionName, '-', '')}${uniqueString(resourceGroup().id, bladeConfig.sectionName)}' + skuName: manageLayerConfig.bastion.skuName + vNetId: vnetId + location: location + enableTelemetry: enableTelemetry + } +} + + +/* +.___ ___. ___ ______ __ __ __ .__ __. _______ +| \/ | / \ / || | | | | | | \ | | | ____| +| \ / | / ^ \ | ,----'| |__| | | | | \| | | |__ +| |\/| | / /_\ \ | | | __ | | | | . ` | | __| +| | | | / _____ \ | `----.| | | | | | | |\ | | |____ +|__| |__| /__/ \__\ \______||__| |__| |__| |__| \__| |_______| +*/ + +resource existingVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = if (enableBastion) { + name: kvName +} + +module virtualMachine './virtual_machine.bicep' = if (enableBastion) { + name: '${bladeConfig.sectionName}-machine' + params: { + vmName: 'vm-${replace(bladeConfig.sectionName, '-', '')}${uniqueString(resourceGroup().id, bladeConfig.sectionName)}' + vmSize: manageLayerConfig.machine.vmSize + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + vmSubnetId: vmSubnetId + vmAdminUsername: vmAdminUsername + vmAdminPasswordOrKey: empty(vmAdminPasswordOrKey) ? existingVault.getSecret('PrivateLinkSSHKey-public') : vmAdminPasswordOrKey + workspaceName: workspaceName + authenticationType: empty(vmAdminPasswordOrKey) ? 'sshPublicKey' : 'password' + } +} diff --git a/bicep/modules/blade_network.bicep b/bicep/modules/blade_network.bicep new file mode 100644 index 00000000..82623aca --- /dev/null +++ b/bicep/modules/blade_network.bicep @@ -0,0 +1,405 @@ +///////////////// +// Network Blade +///////////////// +// import * as type from 'types.bicep' + +type bladeSettings = { + @description('The name of the section name') + sectionName: string + @description('The display name of the section') + displayName: string +} + +type subnetSettings = { + @description('The name of the subnet') + name: string + @description('The address range to use for the subnet') + prefix: string +} + +type vnetSettings = { + @description('The name of the resource group that contains the Virtual Network') + group: string + @description('The name of the Virtual Network') + name: string + @description('The address range to use for the Virtual Network') + prefix: string + @description('The Managed Identity ') + identityId: string + @description('The cluster subnet') + aksSubnet: subnetSettings + @description('The pod subnet') + podSubnet: subnetSettings + @description('The machine subnet') + vmSubnet: subnetSettings + @description('The bastion subnet') + bastionSubnet: subnetSettings +} + +@description('The configuration for the blade section.') +param bladeConfig bladeSettings + +@description('The location of resources to deploy') +param location string + +@description('Feature Flag to Enable Telemetry') +param enableTelemetry bool = false + +@description('The workspace resource Id for diagnostics') +param workspaceResourceId string + +@description('Optional. Bring your own Virtual Network.') +param vnetConfiguration vnetSettings + +@description('Feature Flag to Enable Bastion') +param enableBastion bool + +@description('Feature Flag to Enable a Pod Subnet') +param enablePodSubnet bool + +@description('Feature Flag to Enable a Pod Subnet') +param enableVnetInjection bool + +@description('The Managed Identity Principal Id') +param identityId string + +var networkConfiguration = vnetConfiguration.name == '' ? { + prefix: '10.1.0.0/16' + aksSubnet: { + name: 'ClusterSubnet' + prefix: '10.1.0.0/20' + } + podSubnet: { + name: 'PodSubnet' + prefix: '10.1.20.0/22' + } + vmSubnet: { + name: 'VmSubnet' + prefix: '10.1.18.0/24' + } + bastionSubnet: { + name: 'AzureBastionSubnet' + prefix: '10.1.16.0/24' + } +} : vnetConfiguration + + +var nsgRules = { + ssh_outbound: { + name: 'AllowSshOutbound' + properties: { + priority: 110 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } + + cloud_outbound: { + name: 'AllowAzureCloudOutbound' + properties: { + priority: 120 + protocol: 'Tcp' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'AzureCloud' + destinationPortRange: '443' + } + } + + bastion_communication: { + name: 'AllowBastionCommunication' + properties: { + priority: 130 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + + allow_http_outbound: { + name: 'AllowHttpOutbound' + properties: { + priority: 140 + protocol: '*' + access: 'Allow' + direction: 'Outbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: 'Internet' + destinationPortRange: '80' + } + } + + load_balancer_inbound: { + name: 'AllowAzureLoadBalancerInbound' + properties: { + priority: 160 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'AzureLoadBalancer' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + + bastion_host_communication: { + name: 'AllowBastionHostCommunication' + properties: { + priority: 170 + protocol: '*' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + } + } + + http_inbound_rule: { + name: 'AllowHttpInbound' + properties: { + priority: 200 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '80' + } + } + + https_inbound_rule: { + name: 'AllowHttpsInbound' + properties: { + priority: 210 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'Internet' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '443' + } + } + + ssh_inbound: { + name: 'AllowSshInbound' + properties: { + priority: 220 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + destinationAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '22' + '3389' + ] + } + } +} + +var subnets = { + cluster: { + name: networkConfiguration.aksSubnet.name + addressPrefix: networkConfiguration.aksSubnet.prefix + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + { + service: 'Microsoft.KeyVault' + } + { + service: 'Microsoft.ContainerRegistry' + } + ] + networkSecurityGroupResourceId: !enableVnetInjection ? clusterNetworkSecurityGroup.outputs.resourceId :null + roleAssignments: [ + { + roleDefinitionIdOrName: 'Network Contributor' + principalId: identityId + principalType: 'ServicePrincipal' + } + ] + } + pods: { + name: networkConfiguration.podSubnet.name + addressPrefix: networkConfiguration.podSubnet.prefix + networkSecurityGroupResourceId: !enableVnetInjection ? clusterNetworkSecurityGroup.outputs.resourceId :null + roleAssignments: [ + { + roleDefinitionIdOrName: 'Network Contributor' + principalId: identityId + principalType: 'ServicePrincipal' + } + ] + } + bastion: { + name: networkConfiguration.bastionSubnet.name + addressPrefix: networkConfiguration.bastionSubnet.prefix + networkSecurityGroupResourceId: enableBastion ? bastionNetworkSecurityGroup.outputs.resourceId: null + } + machine: { + name: networkConfiguration.vmSubnet.name + addressPrefix: networkConfiguration.vmSubnet.prefix + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + } + { + service: 'Microsoft.KeyVault' + } + { + service: 'Microsoft.ContainerRegistry' + } + ] + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + networkSecurityGroupResourceId: enableBastion ? machineNetworkSecurityGroup.outputs.resourceId : null + } +} + +module clusterNetworkSecurityGroup 'br/public:avm/res/network/network-security-group:0.1.0' = if (!enableVnetInjection) { + name: '${bladeConfig.sectionName}-nsg-cluster' + params: { + name: 'nsg-common${uniqueString(resourceGroup().id, 'common')}-aks' + location: location + enableTelemetry: enableTelemetry + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + securityRules: union( + array(nsgRules.http_inbound_rule), + array(nsgRules.https_inbound_rule), + array(nsgRules.ssh_outbound) + ) + } +} + +module bastionNetworkSecurityGroup 'br/public:avm/res/network/network-security-group:0.1.0' = if (!enableVnetInjection && enableBastion) { + name: '${bladeConfig.sectionName}-nsg-bastion' + params: { + name: 'nsg-common${uniqueString(resourceGroup().id, 'common')}-bastion' + location: location + enableTelemetry: enableTelemetry + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + securityRules: union( + array(nsgRules.https_inbound_rule), + array(nsgRules.load_balancer_inbound), + array(nsgRules.bastion_host_communication), + array(nsgRules.ssh_outbound), + array(nsgRules.cloud_outbound), + array(nsgRules.bastion_communication), + array(nsgRules.allow_http_outbound) + ) + } +} + +module machineNetworkSecurityGroup 'br/public:avm/res/network/network-security-group:0.1.0' = if (!enableVnetInjection && enableBastion) { + name: '${bladeConfig.sectionName}-nsg-manage' + params: { + name: 'nsg-common${uniqueString(resourceGroup().id, 'common')}-vm' + location: location + enableTelemetry: enableTelemetry + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + securityRules: [] + } +} + +module network 'br/public:avm/res/network/virtual-network:0.1.0' = if (!enableVnetInjection) { + name: '${bladeConfig.sectionName}-virtual-network' + params: { + name: 'vnet-common${uniqueString(resourceGroup().id, 'common')}' + location: location + enableTelemetry: enableTelemetry + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + addressPrefixes: [ + networkConfiguration.prefix + ] + + // Hook up Diagnostics + diagnosticSettings: [ + { + name: 'LogAnalytics' + workspaceResourceId: workspaceResourceId + metricCategories: [ + { + category: 'AllMetrics' + } + ] + } + ] + + // Assign RBAC + roleAssignments: [ + { + roleDefinitionIdOrName: 'Reader' + principalId: identityId + principalType: 'ServicePrincipal' + } + ] + + // Setup Subnets + subnets: union( + array(subnets.cluster), + enablePodSubnet ? array(subnets.pods) : [], + enableBastion ? array(subnets.bastion) : [], + enableBastion ? array(subnets.machine) : [] + ) + } + dependsOn: [ + clusterNetworkSecurityGroup + bastionNetworkSecurityGroup + machineNetworkSecurityGroup + ] +} + +output networkConfiguration object = networkConfiguration +output vnetId string = enableVnetInjection ? resourceId(networkConfiguration.group, 'Microsoft.Network/virtualNetworks', networkConfiguration.name) : network.outputs.resourceId +output aksSubnetId string = enableVnetInjection ? '${resourceId(networkConfiguration.group, 'Microsoft.Network/virtualNetworks', networkConfiguration.name)}/subnets/${networkConfiguration.aksSubnet.name}' : '${network.outputs.resourceId}/subnets/${networkConfiguration.aksSubnet.name}' +output vmSubnetId string = enableVnetInjection ? '${resourceId(networkConfiguration.group, 'Microsoft.Network/virtualNetworks', networkConfiguration.name)}/subnets/${networkConfiguration.vmSubnet.name}' : '${network.outputs.resourceId}/subnets/${networkConfiguration.vmSubnet.name}' +output podSubnetId string = enableVnetInjection ? '${resourceId(networkConfiguration.group, 'Microsoft.Network/virtualNetworks', networkConfiguration.name)}/subnets/${networkConfiguration.podSubnet.name}' : '${network.outputs.resourceId}/subnets/${networkConfiguration.podSubnet.name}' diff --git a/bicep/modules/blade_partition.bicep b/bicep/modules/blade_partition.bicep new file mode 100644 index 00000000..ea5ce7bc --- /dev/null +++ b/bicep/modules/blade_partition.bicep @@ -0,0 +1,378 @@ +///////////////// +// Partition Blade +///////////////// +// import * as type from 'types.bicep' + +type bladeSettings = { + @description('The name of the section name') + sectionName: string + @description('The display name of the section') + displayName: string +} + +@description('The configuration for the blade section.') +param bladeConfig bladeSettings + +@description('The location of resources to deploy') +param location string + +@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.') +param enableBlobPublicAccess bool + +@description('Feature Flag to Enable Private Link') +param enablePrivateLink bool + +@description('The workspace resource Id for diagnostics') +param workspaceResourceId string + +@description('The subnet id for Private Endpoints') +param subnetId string + +@description('Optional. Customer Managed Encryption Key.') +param cmekConfiguration object = { + kvUrl: '' + keyName: '' + identityId: '' +} + +@description('The name of the Key Vault where the secret exists') +param kvName string + +@description('Storage DNS Zone Id') +param storageDNSZoneId string + +@description('Cosmos DNS Zone Id') +param cosmosDNSZoneId string + +@allowed([ + 'CostOptimised' + 'Standard' + 'HighSpec' +]) +@description('The Partition Size') +param partitionSize string = 'CostOptimised' + +@description('List of Data Partitions') +param partitions array = [ + { + name: 'opendes' + } +] + +///////////////////////////////// +// Configuration +///////////////////////////////// +var partitionLayerConfig = { + secrets: { + storageAccountName: 'storage' + storageAccountKey: 'key' + cosmosConnectionString: 'cosmos-connection' + cosmosEndpoint: 'cosmos-endpoint' + cosmosPrimaryKey: 'cosmos-primary-key' + } + storage: { + sku: 'Standard_LRS' + containers: [ + 'legal-service-azure-configuration' + 'osdu-wks-mappings' + 'wdms-osdu' + 'file-staging-area' + 'file-persistent-area' + ] + } + database: { + name: 'osdu-db' + CostOptimised : { + throughput: 2000 + } + Standard: { + throughput: 4000 + } + HighSpec: { + throughput: 12000 + } + backup: 'Continuous' + containers: [ + { + name: 'LegalTag' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'StorageRecord' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'StorageSchema' + kind: 'Hash' + paths: [ + '/kind' + ] + } + { + name: 'TenantInfo' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'UserInfo' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'Authority' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'EntityType' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'SchemaInfo' + kind: 'Hash' + paths: [ + '/partitionId' + ] + } + { + name: 'Source' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'RegisterAction' + kind: 'Hash' + paths: [ + '/dataPartitionId' + ] + } + { + name: 'RegisterDdms' + kind: 'Hash' + paths: [ + '/dataPartitionId' + ] + } + { + name: 'RegisterSubscription' + kind: 'Hash' + paths: [ + '/dataPartitionId' + ] + } + { + name: 'IngestionStrategy' + kind: 'Hash' + paths: [ + '/workflowType' + ] + } + { + name: 'RelationshipStatus' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'MappingInfo' + kind: 'Hash' + paths: [ + '/sourceSchemaKind' + ] + } + { + name: 'FileLocationInfo' + kind: 'Hash' + paths: [ + '/id' + ] + } + { + name: 'WorkflowCustomOperatorInfo' + kind: 'Hash' + paths: [ + '/operatorId' + ] + } + { + name: 'WorkflowV2' + kind: 'Hash' + paths: [ + '/partitionKey' + ] + } + { + name: 'WorkflowRunV2' + kind: 'Hash' + paths: [ + '/partitionKey' + ] + } + { + name: 'WorkflowCustomOperatorV2' + kind: 'Hash' + paths: [ + '/partitionKey' + ] + } + { + name: 'WorkflowTasksSharingInfoV2' + kind: 'Hash' + paths: [ + '/partitionKey' + ] + } + { + name: 'Status' + kind: 'Hash' + paths: [ + '/correlationId' + ] + } + { + name: 'DataSetDetails' + kind: 'Hash' + paths: [ + '/correlationId' + ] + } + ] + } +} + + + +/* +.______ ___ .______ .___________. __ .___________. __ ______ .__ __. _______. +| _ \ / \ | _ \ | || | | || | / __ \ | \ | | / | +| |_) | / ^ \ | |_) | `---| |----`| | `---| |----`| | | | | | | \| | | (----` +| ___/ / /_\ \ | / | | | | | | | | | | | | | . ` | \ \ +| | / _____ \ | |\ \----. | | | | | | | | | `--' | | |\ | .----) | +| _| /__/ \__\ | _| `._____| |__| |__| |__| |__| \______/ |__| \__| |_______/ +*/ + +module partitionStorage './storage-account/main.bicep' = [for (partition, index) in partitions: { + name: '${bladeConfig.sectionName}-azure-storage-${index}' + params: { + #disable-next-line BCP335 BCP332 + name: 'sa${replace('data${index}${substring(uniqueString(partition.name), 0, 6)}', '-', '')}${uniqueString(resourceGroup().id, 'data${index}${substring(uniqueString(partition.name), 0, 6)}')}' + location: location + + // Assign Tags + tags: { + layer: bladeConfig.displayName + partition: partition.name + purpose: 'data' + } + + // Hook up Diagnostics + diagnosticWorkspaceId: workspaceResourceId + diagnosticLogsRetentionInDays: 0 + + // Apply Security + allowBlobPublicAccess: enableBlobPublicAccess + + // Configure Service + sku: partitionLayerConfig.storage.sku + containers: concat(partitionLayerConfig.storage.containers, [partition.name]) + + // Hookup Customer Managed Encryption Key + cmekConfiguration: cmekConfiguration + + // Persist Secrets to Vault + keyVaultName: kvName + storageAccountSecretName: '${partition.name}-${partitionLayerConfig.secrets.storageAccountName}' + storageAccountKeySecretName: '${partition.name}-${partitionLayerConfig.secrets.storageAccountKey}' + } +}] + +module partitionStorageEndpoint './private-endpoint/main.bicep' = [for (partition, index) in partitions: if (enablePrivateLink) { + name: '${bladeConfig.sectionName}-azure-storage-endpoint-${index}' + params: { + resourceName: partitionStorage[index].outputs.name + subnetResourceId: subnetId + serviceResourceId: partitionStorage[index].outputs.id + groupIds: [ 'blob'] + privateDnsZoneGroup: { + privateDNSResourceIds: [storageDNSZoneId] + } + } +}] + +module partitionDb './cosmos-db/main.bicep' = [for (partition, index) in partitions: { + name: '${bladeConfig.sectionName}-cosmos-db-${index}' + params: { + #disable-next-line BCP335 + resourceName: 'data${index}${substring(uniqueString(partition.name), 0, 6)}' + resourceLocation: location + + // Assign Tags + tags: { + layer: bladeConfig.displayName + partition: partition.name + purpose: 'data' + } + + // Hook up Diagnostics + diagnosticWorkspaceId: workspaceResourceId + diagnosticLogsRetentionInDays: 0 + + // Configure Service + sqlDatabases: [ + { + name: partitionLayerConfig.database.name + containers: partitionLayerConfig.database.containers + } + ] + maxThroughput: partitionLayerConfig.database[partitionSize].throughput + backupPolicyType: partitionLayerConfig.database.backup + + // Hookup Customer Managed Encryption Key + systemAssignedIdentity: false + userAssignedIdentities: !empty(cmekConfiguration.identityId) ? { + '${cmekConfiguration.identityId}': {} + } : {} + defaultIdentity: !empty(cmekConfiguration.identityId) ? cmekConfiguration.identityId : '' + kvKeyUri: !empty(cmekConfiguration.kvUrl) && !empty(cmekConfiguration.keyName) ? '${cmekConfiguration.kvUrl}/keys/${cmekConfiguration.keyName}' : '' + + // Persist Secrets to Vault + keyVaultName: kvName + databaseEndpointSecretName: '${partition.name}-${partitionLayerConfig.secrets.cosmosEndpoint}' + databasePrimaryKeySecretName: '${partition.name}-${partitionLayerConfig.secrets.cosmosPrimaryKey}' + databaseConnectionStringSecretName: '${partition.name}-${partitionLayerConfig.secrets.cosmosConnectionString}' + } +}] + +module partitionDbEndpoint './private-endpoint/main.bicep' = [for (partition, index) in partitions: if (enablePrivateLink) { + name: '${bladeConfig.sectionName}-cosmos-db-endpoint-${index}' + params: { + resourceName: partitionDb[index].outputs.name + subnetResourceId: subnetId + serviceResourceId: partitionDb[index].outputs.id + groupIds: [ 'sql'] + privateDnsZoneGroup: { + privateDNSResourceIds: [cosmosDNSZoneId] + } + } +}] + + // Output partitionStorage names +output partitionStorageNames string[] = [for (partition, index) in partitions: partitionStorage[index].outputs.name] diff --git a/bicep/modules/blade_service.bicep b/bicep/modules/blade_service.bicep new file mode 100644 index 00000000..819d710c --- /dev/null +++ b/bicep/modules/blade_service.bicep @@ -0,0 +1,518 @@ +///////////////// +// Service Blade +///////////////// +// import * as type from 'types.bicep' + +type bladeSettings = { + @description('The name of the section name') + sectionName: string + @description('The display name of the section') + displayName: string +} + +@description('The configuration for the blade section.') +param bladeConfig bladeSettings + +@description('The location of resources to deploy') +param location string + +@description('Feature Flag to Enable Telemetry') +param enableTelemetry bool + +@description('The workspace resource Id for diagnostics') +param workspaceResourceId string + +param networkPlugin string + +param clusterSize string + +@description('The name of the Key Vault where the secret exists') +param kvName string + +@description('The Uri of the Key Vault where the secret exists') +param kvUri string + +@description('The name of the Storage Account') +param storageName string + + + +@description('Software GIT Repository URL') +param softwareRepository string + +@description('Software GIT Repository Branch') +param softwareBranch string + +@allowed([ + 'Internal' + 'External' + 'Both' +]) +@description('The Cluster Ingress Mode') +param clusterIngress string + +@description('Optional: Specify the AD Users and/or Groups that can manage the cluster.') +param clusterAdminIds array + +@minLength(9) +@maxLength(18) +@description('The address range to use for services') +param serviceCidr string + +@minLength(9) +@maxLength(18) +@description('The address range to use for the docker bridge') +param dockerBridgeCidr string + +@minLength(7) +@maxLength(15) +@description('The IP address to reserve for DNS') +param dnsServiceIP string + + +param aksSubnetId string + +param podSubnetId string = '' + +@description('The managed identity name for deployment scripts') +param managedIdentityName string + +@description('The user managed identity for the cluster.') +param identityId string + +@description('The name of the partition storage accounts') +param partitionStorageNames string[] + + +@description('Feature Flag to Load Software.') +param enableSoftwareLoad bool + +///////////////////////////////// +// Configuration +///////////////////////////////// + +var serviceLayerConfig = { + // name: 'service' + // displayName: 'Service Resources' + cluster: { + aksVersion: '1.28' + meshVersion: 'asm-1-18' + networkPlugin: networkPlugin + } + gitops: { + name: 'flux-system' + url: softwareRepository == '' ? 'https://github.com/azure/osdu-developer' : softwareRepository + branch: softwareBranch == '' ? 'main' : softwareBranch + components: './stamp/components' + applications: './stamp/applications' + } + imageList: { + None: [] + M22: [ + 'community.opengroup.org:5555/osdu/platform/system/partition/partition-v0-24-0:latest' + 'community.opengroup.org:5555/osdu/platform/security-and-compliance/entitlements/entitlements-v0-24-0:latest' + 'community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/legal-v0-24-0:latest' + 'community.opengroup.org:5555/osdu/platform/system/schema-service/schema-service-release-0-24:latest' + 'community.opengroup.org:5555/osdu/platform/system/storage/storage-v0-24-0:latest' + 'community.opengroup.org:5555/osdu/platform/system/file/file-v0-24-0:latest' + 'community.opengroup.org:5555/osdu/platform/system/indexer-service/indexer-service-v0-24-0:latest' + 'community.opengroup.org:5555/osdu/platform/system/search-service/search-service-v0-24-0:latest' + ] + } +} + + +/* - + __ ___ __ __ .______ _______ .______ .__ __. _______ .___________. _______ _______. +| |/ / | | | | | _ \ | ____|| _ \ | \ | | | ____|| || ____| / | +| ' / | | | | | |_) | | |__ | |_) | | \| | | |__ `---| |----`| |__ | (----` +| < | | | | | _ < | __| | / | . ` | | __| | | | __| \ \ +| . \ | `--' | | |_) | | |____ | |\ \----.| |\ | | |____ | | | |____.----) | +|__|\__\ \______/ |______/ |_______|| _| `._____||__| \__| |_______| |__| |_______|_______/ +*/ + +// This is used to help determine what the default subnet should be for the Pods if vnet injected is enabled +// var defaultPodSubnetId = enableVnetInjection ? '${resourceId(networkConfiguration.group, 'Microsoft.Network/virtualNetworks', networkConfiguration.name)}/subnets/${podSubnetName}' : '${network.outputs.resourceId}/subnets/${podSubnetName}' + +module cluster './aks_cluster.bicep' = { + name: '${bladeConfig.sectionName}-aks-cluster' + params: { + // Basic Details + resourceName: bladeConfig.sectionName + location: location + aksVersion: serviceLayerConfig.cluster.aksVersion + aad_tenant_id: subscription().tenantId + clusterSize: clusterSize + networkPlugin: serviceLayerConfig.cluster.networkPlugin + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + + // Configure Linking Items + aksSubnetId: aksSubnetId + aksPodSubnetId: podSubnetId == '' ? null : podSubnetId + identityId: identityId + workspaceId: workspaceResourceId + + // Configure VNET Injection + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + dockerBridgeCidr: dockerBridgeCidr + + // Configure Istio + serviceMeshProfile: 'Istio' + istioRevision: serviceLayerConfig.cluster.meshVersion + istioIngressGatewayMode: clusterIngress + + // Configure Add Ons + enable_aad: empty(clusterAdminIds) == true ? false : true + admin_ids: clusterAdminIds + workloadIdentityEnabled: true + oidcIssuer: true + keyvaultEnabled: true + fluxGitOpsAddon: true + enableImageCleaner: true + fileCSIDriver: true + blobCSIDriver: true + azurepolicy: 'audit' + } +} + +///////////////// +// Elastic Configuration +///////////////// +var elasticPoolPresets = { + // 4 vCPU, 15 GiB RAM, 28 GiB SSD, (12800) IOPS, Ephemeral OS Disk + CostOptimised : { + vmSize: 'Standard_DS3_v2' + } + // 8 vCPU, 28 GiB RAM, 56 GiB SSD, (32000) IOPS, Ephemeral OS Disk + Standard : { + vmSize: 'Standard_DS4_v2' + } + // 16 vCPU, 56 GiB RAM, 112 GiB SSD, (64000) IOPS, Ephemeral OS Disk + HighSpec : { + vmSize: 'Standard_DS5_v2' + } +} + +module pool1 './aks_agent_pool.bicep' = { + name: '${bladeConfig.sectionName}-pool1' + params: { + AksName: cluster.outputs.aksClusterName + PoolName: 'poolz1' + agentVMSize: elasticPoolPresets[clusterSize].vmSize + agentCount: 2 + agentCountMax: 4 + availabilityZones: [ + '1' + ] + subnetId: aksSubnetId + podSubnetId: podSubnetId + nodeTaints: ['app=cluster:NoSchedule'] + nodeLabels: { + app: 'cluster' + } + } +} + +module pool2 './aks_agent_pool.bicep' = { + name: '${bladeConfig.sectionName}-pool2' + params: { + AksName: cluster.outputs.aksClusterName + PoolName: 'poolz2' + agentVMSize: elasticPoolPresets[clusterSize].vmSize + agentCount: 2 + agentCountMax: 4 + availabilityZones: [ + '2' + ] + subnetId: aksSubnetId + podSubnetId: podSubnetId + nodeTaints: ['app=cluster:NoSchedule'] + nodeLabels: { + app: 'cluster' + } + } +} + +module pool3 './aks_agent_pool.bicep' = { + name: '${bladeConfig.sectionName}-pool3' + params: { + AksName: cluster.outputs.aksClusterName + PoolName: 'poolz3' + agentVMSize: elasticPoolPresets[clusterSize].vmSize + agentCount: 2 + agentCountMax: 4 + availabilityZones: [ + '3' + ] + subnetId: aksSubnetId + podSubnetId: podSubnetId + nodeTaints: ['app=cluster:NoSchedule'] + nodeLabels: { + app: 'cluster' + } + } +} + + +///////////////// +// Workload Identity Federated Credentials +///////////////// +module appIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.1.0' = { + name: '${bladeConfig.sectionName}-user-managed-identity' + params: { + // Required parameters + name: 'id-${replace(bladeConfig.sectionName, '-', '')}${uniqueString(resourceGroup().id, bladeConfig.sectionName)}' + location: location + enableTelemetry: enableTelemetry + + // Only support 1. https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-considerations#concurrent-updates-arent-supported-user-assigned-managed-identities + federatedIdentityCredentials: [{ + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: cluster.outputs.aksOidcIssuerUrl + name: 'federated-ns_default' + subject: 'system:serviceaccount:default:workload-identity-sa' + }] + + // Assign Tags + tags: { + layer: bladeConfig.displayName + } + } +} + +// Federated Credentials have to be sequentially added. Ensure depends on. +module federatedCredsDevSample './federated_identity.bicep' = { + name: '${bladeConfig.sectionName}-federated-cred-ns_dev-sample' + params: { + name: 'federated-ns_dev-sample' + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: cluster.outputs.aksOidcIssuerUrl + userAssignedIdentityName: appIdentity.outputs.name + subject: 'system:serviceaccount:dev-sample:workload-identity-sa' + } + dependsOn: [ + appIdentity + ] +} + +module federatedCredsConfigMaps './federated_identity.bicep' = { + name: '${bladeConfig.sectionName}-federated-cred-ns_config-maps' + params: { + name: 'federated-ns_azappconfig-system' + audiences: [ + 'api://AzureADTokenExchange' + ] + issuer: cluster.outputs.aksOidcIssuerUrl + userAssignedIdentityName: appIdentity.outputs.name + subject: 'system:serviceaccount:azappconfig-system:az-appconfig-k8s-provider' + } + dependsOn: [ + federatedCredsDevSample + ] +} + +module appRoleAssignments './app_assignments.bicep' = { + name: '${bladeConfig.sectionName}-user-managed-identity-rbac' + params: { + identityprincipalId: appIdentity.outputs.principalId + kvName: kvName + storageName: storageName + } + dependsOn: [ + federatedCredsConfigMaps + ] +} + +module appRoleAssignments2 './app_assignments.bicep' = [for (name, index) in partitionStorageNames: { + name: '${bladeConfig.sectionName}-user-managed-identity-rbac-${name}' + params: { + identityprincipalId: appIdentity.outputs.principalId + storageName: name + } + dependsOn: [ + federatedCredsDevSample + ] +}] + +///////////////// +// Helm Charts +///////////////// +module helmAppConfigProvider './aks-run-command/main.bicep' = { + name: '${bladeConfig.sectionName}-helm-appconfig-provider' + params: { + aksName: cluster.outputs.aksClusterName + location: location + + newOrExistingManagedIdentity: 'existing' + managedIdentityName: managedIdentityName + existingManagedIdentitySubId: subscription().subscriptionId + existingManagedIdentityResourceGroupName:resourceGroup().name + + commands: [ + 'helm install azureappconfiguration.kubernetesprovider oci://mcr.microsoft.com/azure-app-configuration/helmchart/kubernetes-provider --namespace azappconfig-system --create-namespace' + ] + } +} + + + +/* + ___ .______ .______ ______ ______ .__ __. _______ __ _______ + / \ | _ \ | _ \ / | / __ \ | \ | | | ____|| | / _____| + / ^ \ | |_) | | |_) | | ,----'| | | | | \| | | |__ | | | | __ + / /_\ \ | ___/ | ___/ | | | | | | | . ` | | __| | | | | |_ | + / _____ \ | | | | | `----.| `--' | | |\ | | | | | | |__| | +/__/ \__\ | _| | _| \______| \______/ |__| \__| |__| |__| \______| +*/ + +var appSettings = [ + { + name: 'Settings:Message' + value: 'Hello from App Configuration' + contentType: 'text/plain' + label: 'configmap-devsample' + } + { + name: 'Settings:StorageAccountName' + value: partitionStorageNames[0] + contentType: 'text/plain' + label: 'configmap-devsample' + } +] + +module app_config './app-configuration/main.bicep' = { + name: '${bladeConfig.sectionName}-appconfig' + params: { + resourceName: bladeConfig.sectionName + location: location + tags: { + layer: bladeConfig.displayName + } + + // Add Role Assignment + roleAssignments: [ + { + roleDefinitionIdOrName: 'App Configuration Data Reader' + principalIds: [ + appIdentity.outputs.principalId + ] + principalType: 'ServicePrincipal' + } + ] + + // Add Configuration + keyValues: concat(appSettings) + } + dependsOn: [ + appRoleAssignments + appRoleAssignments2 + ] +} + +@description('The name of the azure keyvault.') +output ENV_CONFIG_ENDPOINT string = app_config.outputs.endpoint + +//--------------Config Map--------------- +// SecretProviderClass --> tenantId, clientId, keyvaultName +// ServiceAccount --> tenantId, clientId +// AzureAppConfigurationProvider --> tenantId, clientId, configEndpoint, keyvaultUri +var configMaps = { + appConfigTemplate: ''' +values.yaml: | + serviceAccount: + create: false + name: "workload-identity-sa" + azure: + tenantId: {0} + clientId: {1} + configEndpoint: {2} + keyvaultUri: {3} + keyvaultName: {4} + ''' +} + +module appConfigMap './aks-config-map/main.bicep' = { + name: '${bladeConfig.sectionName}-cluster-appconfig-configmap' + params: { + aksName: cluster.outputs.aksClusterName + location: location + name: 'config-map-values' + namespace: 'default' + // Order of items matters here. + fileData: [ + format(configMaps.appConfigTemplate, + subscription().tenantId, + appIdentity.outputs.clientId, + app_config.outputs.endpoint, + kvUri, + kvName) + ] + } +} + + + +/* _______ __ .___________. ______ .______ _______. + / _____|| | | | / __ \ | _ \ / | +| | __ | | `---| |----`| | | | | |_) | | (----` +| | |_ | | | | | | | | | | ___/ \ \ +| |__| | | | | | | `--' | | | .----) | + \______| |__| |__| \______/ | _| |_______/ +*/ + +//--------------Flux Config--------------- +module fluxConfiguration 'br/public:avm/res/kubernetes-configuration/flux-configuration:0.3.1' = if(enableSoftwareLoad) { + name: '${bladeConfig.sectionName}-cluster-gitops' + params: { + name: serviceLayerConfig.gitops.name + location: location + namespace: cluster.outputs.fluxReleaseNamespace + clusterName: cluster.outputs.aksClusterName + scope: 'cluster' + sourceKind: 'GitRepository' + gitRepository: { + url: serviceLayerConfig.gitops.url + timeoutInSeconds: 180 + syncIntervalInSeconds: 300 + repositoryRef: { + branch: serviceLayerConfig.gitops.branch + } + } + kustomizations: { + components: { + path: serviceLayerConfig.gitops.components + timeoutInSeconds: 300 + syncIntervalInSeconds: 300 + retryIntervalInSeconds: 300 + prune: true + } + applications: { + path: serviceLayerConfig.gitops.applications + dependsOn: [ + 'components' + ] + timeoutInSeconds: 300 + syncIntervalInSeconds: 300 + retryIntervalInSeconds: 300 + prune: true + } + } + } + dependsOn: [ + app_config + appConfigMap + pool1 + pool2 + pool3 + ] +} + diff --git a/bicep/modules/keyvault_secrets.bicep b/bicep/modules/keyvault_secrets.bicep index ae2fb4e5..a9a8482f 100644 --- a/bicep/modules/keyvault_secrets.bicep +++ b/bicep/modules/keyvault_secrets.bicep @@ -10,13 +10,6 @@ param workspaceIdName string @description('Required. The name of the secret.') param workspaceKeySecretName string -@description('Required. The name of the secret.') -param stampIdName string - -@description('Required. The name of the secret.') -@secure() -param stampIdValue string - resource logAnaltyics 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { name: workspaceName } @@ -43,11 +36,4 @@ resource idSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { } } -resource stampId 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { - name: stampIdName - parent: keyVault - - properties: { - value: stampIdValue - } -} +output name string = keyVault.name diff --git a/bicep/modules/virtual_machine.bicep b/bicep/modules/virtual_machine.bicep index 5a1c7c96..dbeda612 100644 --- a/bicep/modules/virtual_machine.bicep +++ b/bicep/modules/virtual_machine.bicep @@ -63,6 +63,7 @@ param location string = resourceGroup().location @description('Specifies the resource tags.') param tags object + // Variables var vmNicName = '${vmName}Nic' var linuxConfiguration = { @@ -78,6 +79,7 @@ var linuxConfiguration = { provisionVMAgent: true } + // Resources resource virtualMachineNic 'Microsoft.Network/networkInterfaces@2023-06-01' = { name: vmNicName diff --git a/bicepconfig.json b/bicepconfig.json index 846ce8ba..6e233702 100644 --- a/bicepconfig.json +++ b/bicepconfig.json @@ -1,34 +1,35 @@ { - "analyzers": { - "core": { - "enabled": true, - "rules": { - "no-hardcoded-env-urls": { - "level": "off" - }, - "explicit-values-for-loc-params": { - "level": "off" - }, - "no-unnecessary-dependson": { - "level": "off" - }, - "no-unused-params": { - "level": "warning" - }, - "no-unused-vars": { - "level": "warning" - }, - "prefer-interpolation": { - "level": "warning" - }, - "secure-parameter-default": { - "level": "warning" - }, - "simplify-interpolation": { - "level": "warning" - } + "experimentalFeaturesEnabled": { + }, + "analyzers": { + "core": { + "enabled": true, + "rules": { + "no-hardcoded-env-urls": { + "level": "off" + }, + "explicit-values-for-loc-params": { + "level": "off" + }, + "no-unnecessary-dependson": { + "level": "off" + }, + "no-unused-params": { + "level": "warning" + }, + "no-unused-vars": { + "level": "warning" + }, + "prefer-interpolation": { + "level": "warning" + }, + "secure-parameter-default": { + "level": "warning" + }, + "simplify-interpolation": { + "level": "warning" } } } } - \ No newline at end of file +} \ No newline at end of file diff --git a/docs/vnet-injection.md b/docs/vnet-injection.md index bd2db2f2..5aff3475 100644 --- a/docs/vnet-injection.md +++ b/docs/vnet-injection.md @@ -1,12 +1,13 @@ # Virtual Network Injection -The provided custom deployment solution is a sample of how to enable and use virtual network (VNet) injection, allowing the creation of a network prior to deploying the solution. This is particularly beneficial in organizations with specific network security policies. Below is a tutorial that shows an example of a simple deployment leveraging network injection. +The provided custom deployment solution is a sample of how to leverage the virtual network (VNet) injection feature. This allows for the integration of the solution into a preexisting network design and ensuring the solution is on an internal network. + ## Planning -Network planning is crucial when working with AKS and a workload for AKS. This is an advanced topic and the assumption when bringing your own network is that it has been planned properly. +Network planning is crucial when working with AKS on a prexexisting network solution. This is an advanced topic and the assumption when bringing your own network is that it has been planned properly in advance. -Several resources exist that can help on planning networks for AKS and to understand the networking concepts of AKS. +Several resources exist that can help on planning networks for AKS and to understand the networking concepts for AKS. - [AKS Network Topology and Connectivity](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/app-platform/aks/network-topology-and-connectivity) @@ -16,7 +17,7 @@ Several resources exist that can help on planning networks for AKS and to unders __Default Solution__ -The default implementation uses a simple Virtual Network with a Kubenet plugin. One subnet which is provided to the AKS cluster is required, and additional subnets can be enabled for Bastion, VPN Gateway etc. +The default implementation uses a simple Virtual Network with a Kubenet plugin. One subnet which is provided to the AKS cluster is required, and additional subnets can be enabled for Bastion. - Virtual Network CIDR: `10.1.0.0/16` @@ -36,7 +37,7 @@ The default implementation uses a simple Virtual Network with a Kubenet plugin. __Custom Solution__ -This custom configuration tutorial will use a pre-created network along with a dedicated Pod Subnet which activates the `Azure CNI` network plugin. +This custom configuration tutorial will use a pre-created network along with a dedicated Pod Subnet which activates the [Azure CNI for dynamic IP allocation](https://learn.microsoft.com/en-us/azure/aks/configure-azure-cni-dynamic-ip-allocation) network configuration. Things to considered when planning. @@ -105,14 +106,14 @@ az network nsg create --name $NSG_NAME \ az network nsg rule create --name AllowHttpInbound \ --nsg-name $NSG_NAME --resource-group $NETWORK_GROUP \ --priority 200 --access Allow --direction Inbound \ ---protocol 'Tcp' --source-address-prefixes 'Internet' --source-port-ranges '*' \ +--protocol 'Tcp' --source-address-prefixes 'VirtualNetwork' --source-port-ranges '*' \ --destination-address-prefixes '*' --destination-port-ranges '80' # https_inbound_rule az network nsg rule create --name AllowHttpsInbound \ --nsg-name $NSG_NAME --resource-group $NETWORK_GROUP \ --priority 210 --access Allow --direction Inbound \ ---protocol 'Tcp' --source-address-prefixes 'Internet' --source-port-ranges '*' \ +--protocol 'Tcp' --source-address-prefixes 'VirtualNetwork' --source-port-ranges '*' \ --destination-address-prefixes '*' --destination-port-ranges '443' ``` @@ -127,10 +128,10 @@ Use the following commands set up the network with a required subnet for the clu NETWORK_NAME='custom-vnet' VNET_PREFIX='172.18.0.0/22' -CLUSTER_SUBNET_NAME='subnet1' +CLUSTER_SUBNET_NAME='cluster' CLUSTER_SUBNET_PREFIX='172.18.0.0/24' -POD_SUBNET_NAME='subnet2' +POD_SUBNET_NAME='pods' POD_SUBNET_PREFIX='172.18.1.0/24' # virtual_network @@ -172,56 +173,6 @@ azd auth login azd init -e custom ``` -__Create Parameters__ - -```json -cat < bicep/main.parameters.json -{ - "\$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "applicationClientId": { - "value": "\${AZURE_CLIENT_ID}" - }, - "enablePodSubnet": { - "value": "\${ENABLE_POD_SUBNET}" - }, - "softwareRepository": { - "value": "\${SOFTWARE_REPOSITORY}" - }, - "softwareBranch": { - "value": "\${SOFTWARE_BRANCH}" - }, - "virtualNetworkNewOrExisting": { - "value": "Existing" - }, - "virtualNetworkResourceGroup": { - "value": "\${VIRTUAL_NETWORK_GROUP}" - }, - "virtualNetworkName": { - "value": "\${VIRTUAL_NETWORK_NAME}" - }, - "virtualNetworkAddressPrefix": { - "value": "\${VIRTUAL_NETWORK_PREFIX}" - }, - "aksSubnetName": { - "value": "\${AKS_SUBNET_NAME}" - }, - "aksSubnetAddressPrefix": { - "value": "\${AKS_SUBNET_PREFIX}" - }, - "podSubnetName": { - "value": "\${POD_SUBNET_NAME}" - }, - "podSubnetAddressPrefix": { - "value": "\${POD_SUBNET_PREFIX}" - } - } -} -EOF - -``` - __Configure Environment Variables__ Set the necessary environment variables for your deployment: @@ -235,8 +186,9 @@ azd env set AZURE_CLIENT_ID $(az ad app list --display-name $APP_NAME --query "[ azd env set SOFTWARE_REPOSITORY https://github.com/azure/osdu-developer azd env set SOFTWARE_BRANCH main -# enable_pod_subnet +# enable_feature_toggles azd env set ENABLE_POD_SUBNET true +azd env set ENABLE_VNET_INJECTION true # define_network_configuration azd env set VIRTUAL_NETWORK_GROUP $NETWORK_GROUP @@ -256,4 +208,3 @@ Initiate the deployment using the following command: # provision_solution azd provision ``` - diff --git a/scripts/Dockerfile-provision b/scripts/Dockerfile-provision new file mode 100644 index 00000000..5e3eb556 --- /dev/null +++ b/scripts/Dockerfile-provision @@ -0,0 +1,23 @@ +FROM mcr.microsoft.com/cbl-mariner/base/azure-cli:2 + +# Install required packages +RUN tdnf update -y && \ + tdnf install -y curl gawk ncurses && \ + rm -rf /var/cache/tdnf/* + +# Install azd +RUN curl -fsSL https://aka.ms/install-azd.sh | bash + +# Copy the script into the container +COPY functions.sh /usr/local/bin/functions.sh +COPY hook-preprovision.sh /usr/local/bin/preprovision.sh + +# Create a directory to work in +WORKDIR /workspace + +# Make the script executable +RUN chmod +x /usr/local/bin/functions.sh \ + && chmod +x /usr/local/bin/preprovision.sh + +# Set the entrypoint to run your script +CMD ["/bin/bash"] diff --git a/scripts/functions.sh b/scripts/functions.sh new file mode 100755 index 00000000..57b56170 --- /dev/null +++ b/scripts/functions.sh @@ -0,0 +1,73 @@ +############################### +## FUNCTIONS ## +############################### + +PrintMessage(){ + # Required Argument $1 = Message + + # +---------+---------+ + # | Color | Value | + # +---------+---------+ + # | black | 0 | + # | red | 1 | + # | green | 2 | + # | yellow | 3 | + # | blue | 4 | + # | magenta | 5 | + # | cyan | 6 | + # | white | 7 | + + local _color="${2:-2}" + + if [[ ! -z "$1" ]]; then + if [[ -t 1 ]]; then # Check if stdout is a tty + tput setaf $_color; echo " $1" ; tput sgr0 + else + echo " $1" + fi + fi +} + +function Verify(){ + # Required Argument $1 = Value to check + # Required Argument $2 = Value description for error + + if [[ -z $1 ]]; then + echo "$2 is required and was not provided" + exit 1 + fi +} + +function SetAzureContext() +{ + # Required Argument $1 = SUBSCRIPTION + Verify $1 'SetAzureContext-ERROR: Argument (SUBSCRIPTION) not received' + + local _subscription=$1 + + az account set --subscription $1 + PrintMessage "Account Set: $(az account show --query name -o tsv)" +} + +function CreateResourceGroup() { + # Required Argument $1 = RESOURCE_GROUP + # Required Argument $2 = LOCATION + + Verify $1 'CreateResourceGroup-ERROR: Argument (RESOURCE_GROUP) not received' + Verify $2 'CreateResourceGroup-ERROR: Argument (LOCATION) not received' + + local _result=$(az group show --name $1 2>/dev/null) + if [[ "$_result" == "" ]]; then + az group create --name $1 \ + --location $2 \ + --tags CONTACT=$AZURE_USER VERSION=$VERSION REPO_PATH=$REPO_PATH \ + -o none + PrintMessage " Resource Group Created." + else + az tag update --resource-id /subscriptions/$CP_SUBSCRIPTION_ID/resourcegroups/$1 \ + --operation replace \ + --tags CONTACT=$AZURE_USER VERSION=$VERSION REPO_PATH=$REPO_PATH \ + -o none + PrintMessage " Resource Group: $1 --> Already exists." + fi +} diff --git a/scripts/hook-preprovision.sh b/scripts/hook-preprovision.sh new file mode 100755 index 00000000..4fcb4763 --- /dev/null +++ b/scripts/hook-preprovision.sh @@ -0,0 +1,181 @@ +#!/bin/bash + +############################################################################################### +# ---------------------------- # +# preProvision - Pre Provision # +# ---------------------------- # +# # +# Usage: ./hook-preprovision.sh # +# # +# Prerequisites: # +# 1. Ensure you have Azure CLI installed, and you're logged in to Azure CLI. # +# # +# Options: # +# -s : Specify a particular subscriptionId to use. # +# -h : Print help message and exit # +# # +# Note: # +# You must provide a subscription ID # +# # +############################################################################################### + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +PARENT_DIR=`dirname $SCRIPT_DIR` +ROOT_DIR=`dirname $PARENT_DIR` + +if [[ $SCRIPT_DIR == "/usr/local/bin" ]] +then + ROOT_DIR="/workspace" +else + ROOT_DIR=`dirname $PARENT_DIR` +fi + +print_help() { + echo -e "Usage: $0 --subscription SUBSCRIPTION_ID\n" + echo -e "Options:" + echo -e " -s Set the subscription ID" + echo -e " -h Print this help message and exit" + echo -e "\nYou must provide a SubscriptionId." +} + +# Parsing command-line arguments +AZURE_SUBSCRIPTION="" +while getopts ":hs:" opt; do + case ${opt} in + h ) + print_help + exit 0 + ;; + s ) + AZURE_SUBSCRIPTION=$OPTARG + ;; + \? ) + echo "Invalid option: -$OPTARG" >&2 + print_help + exit 1 + ;; + : ) + echo "Option -$OPTARG requires an argument." >&2 + print_help + exit 1 + ;; + esac +done +shift $((OPTIND -1)) + +############################### +# Checks +if [[ -z "$AZURE_SUBSCRIPTION" ]]; +then + echo "Error: You must provide a SubscriptionId" >&2 + print_help + exit 1 +fi + +# Check Azure CLI version. +REQUIRED_AZ_CLI_VERSION="2.53.0" +CURRENT_AZ_CLI_VERSION="$(az --version | head -n 1 | awk -F' ' '{print $2}')" + +if [[ $(echo -e "$REQUIRED_AZ_CLI_VERSION\n$CURRENT_AZ_CLI_VERSION"|sort -V|head -n1) != $REQUIRED_AZ_CLI_VERSION ]]; then + echo "This script requires Azure CLI version $REQUIRED_AZ_CLI_VERSION or higher. You have version $CURRENT_AZ_CLI_VERSION." + exit 1 +fi + +############################### +# Require Common Functions +if [[ -f "$SCRIPT_DIR/functions.sh" ]]; then + source "$SCRIPT_DIR/functions.sh" +fi + + +############################### +## Feature Check ## +############################### +printf "\n" +PrintMessage "==================================================================" 4 +PrintMessage "Ensuring Proper Features are enabled." 4 +PrintMessage "==================================================================" 4 + +PrintMessage " Checking [aks-preview] extension..." +az extension show --name aks-preview &>/dev/null + +if [[ $? == 0 ]]; then + PrintMessage " Found and updating..." + az extension update --name aks-preview &>/dev/null +else + PrintMessage " Not Found and installing..." + + # Install aks-preview extension + az extension add --name aks-preview 1>/dev/null + + if [[ $? == 0 ]]; then + PrintMessage " [aks-preview] extension successfully installed" + else + PrintMessage " Failed to install [aks-preview] extension" + exit + fi +fi + +# Registering AKS feature extensions +aksExtensions=( + "AzureServiceMeshPreview" + "PodSecurityPolicyPreview" + "KubeletDisk" + "AKS-KedaPreview" + "RunCommandPreview" + "EnablePodIdentityPreview" + "UserAssignedIdentityPreview" + "EnablePrivateClusterPublicFQDN" + "PodSubnetPreview" + "EnableOIDCIssuerPreview" + "EnableWorkloadIdentityPreview" + "EnableImageCleanerPreview" + "AKS-VPAPreview" + "AzureOverlayPreview" + "KubeProxyConfigurationPreview" +) + + +ok=0 +registeringExtensions=() +for aksExtension in ${aksExtensions[@]}; do + + PrintMessage " Checking if [$aksExtension] extension is already registered..." + extension=$(az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/$aksExtension') && @.properties.state == 'Registered'].{Name:name}" --output tsv) + + if [[ -z $extension ]]; then + PrintMessage " [$aksExtension] extension is not registered." + PrintMessage " Registering [$aksExtension] extension..." + + az feature register --name $aksExtension --namespace Microsoft.ContainerService + registeringExtensions+=("$aksExtension") + ok=1 + else + PrintMessage " [$aksExtension] extension is already registered." + fi +done + + +PrintMessage $registeringExtensions +delay=1 + +for aksExtension in ${registeringExtensions[@]}; do + PrintMessage " Checking if [$aksExtension] extension is already registered..." + + while true; do + extension=$(az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/$aksExtension') && @.properties.state == 'Registered'].{Name:name}" --output tsv) + if [[ -z $extension ]]; then + echo -n "." + sleep $delay + else + echo "." + break + fi + done +done + +if [[ $ok == 1 ]]; then + PrintMessage " Refreshing the registration of the Microsoft.ContainerService resource provider..." + az provider register --namespace Microsoft.ContainerService + PrintMessage " Microsoft.ContainerService resource provider registration successfully refreshed" +fi \ No newline at end of file